Paolo Zinesi 2053062

set.seed(12345)

library(tidyverse)
library(gridExtra)

cbPalette <- c("#000000", "#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7")

Exercise 1

The number of particles emitted by a radioactive source during a fixed interval of time (∆t = 10 s) follows a Poisson distribution on the parameter \(\mu\). The number of particles observed during consecutive time intervals is: \[\{ 4, 1, 3, 1, 3 \}\]

We use priors that are conjugate to the likelihood. For a Poisson process the conjugate prior is a Gamma distribution, which PDF is \(\text{Gamma} \left(y\,|\,\alpha,\lambda \right) = \dfrac{\lambda^{\alpha}}{\Gamma{(\alpha)}}\, y^{\alpha-1}\, e^{-\lambda\, y}\). If the prior has the form \(\text{Gamma} \left(\alpha,\lambda \right)\) and we have \(n\) observations with results \(\{y_i\}\), the posterior has the form \(\text{Gamma}\left(\alpha + \sum_i y_i, \,\lambda + n \right)\). The mean of a \(\text{Gamma} \left(\alpha,\lambda \right)\) distribution is \(\dfrac{\alpha}{\lambda}\) and the variance is \(\dfrac{\alpha}{\lambda^2}\)

res <- c(4, 1, 3, 1, 3)
mu <- seq(0, 10, length.out=1000)
N_dl <- length(mu) - 1
dl <- (max(mu) - min(mu)) / N_dl

Exercise 1a

Suppose a uniform prior distribution for the parameter \(\mu\). Determine and draw the posterior distribution for \(\mu\), given the data \(D=\{y_i\}\).

A uniform prior has the form \(\text{Gamma} \left(1,0 \right)\), so the posterior has the form \(\text{Gamma} \left(1+\sum_i y_i, \,0 + n \right)\).

# prior
log_prior <- ifelse(mu>=0, 0, -Inf)

# likelihood
log_likl <- 0
for (r_ in res) {
  log_likl <- log_likl + dpois(x=r_, lambda=mu, log=TRUE)
}

# posterior
post_U <- exp(log_likl + log_prior)
post_U <- post_U / (dl * sum(post_U))

# plot posterior
post_U_plt <- ggplot() +
              labs(title=paste0("Posterior = Gamma(", 1+sum(res),",", length(res),")", collapse=""), subtitle="Corresponding to a uniform prior") +
              geom_line(data = data.frame(mu=mu, post=post_U), aes(x=mu, y=post), color="steelblue", size=1) +
              scale_y_continuous(name = expression(paste("P( ", mu, " | D,M )"))) +
              scale_x_continuous(name = expression(mu)) +
              theme_bw() +
              theme(plot.title=element_text(hjust=0.5), plot.subtitle=element_text(hjust=0.5))
post_U_plt

Evaluate mean, median and variance, both analytically and numerically in R.

mean_num_U <- sum(mu*post_U) * dl
median_num_U <- mu[sum(cumsum(post_U * dl) <= 0.5) + 1]
var_num_U <- sum(mu * mu * post_U * dl) - (mean_num_U * mean_num_U)
mean_an_U <- (1 + sum(res)) / length(res)
median_an_U <- qgamma(0.5, shape=1+sum(res), rate=length(res))
var_an_U <- (1 + sum(res)) / length(res)**2

cat("Mean numerical = ", mean_num_U, "; ", "Mean analytical = ", mean_an_U, "\n", sep="")
Mean numerical = 2.6; Mean analytical = 2.6
cat("Median numerical = ", median_num_U, "; ", "Median analytical = ", median_an_U, "\n", sep="")
Median numerical = 2.532533; Median analytical = 2.533646
cat("Variance numerical = ", var_num_U, "; ", "Variance analytical = ", var_an_U, "\n", sep="")
Variance numerical = 0.52; Variance analytical = 0.52
post_U_plt <- post_U_plt +
              geom_vline(mapping=aes(xintercept = mean_an_U, color="Mean"), linetype="dashed", size=0.5) +
              geom_vline(mapping=aes(xintercept = median_an_U, color="Median"), linetype="dashed", size=0.5) +
              scale_color_manual(values = cbPalette, name="Values")
post_U_plt

Exercise 1b

Suppose a Jeffrey’s prior for the parameter \(\mu\). Determine and draw the posterior distribution for \(\mu\), given the data.

A Jeffrey’s prior has the form \(\text{Gamma} \left(\dfrac{1}{2},0 \right)\), so the posterior has the form \(\text{Gamma} \left(\dfrac{1}{2}+\sum_i y_i, \,0 + n \right)\).

# prior
log_prior <- ifelse(mu > 0, -0.5*log(mu), -Inf)

# likelihood
log_likl <- 0
for (r_ in res) {
  log_likl <- log_likl + dpois(x=r_, lambda=mu, log=TRUE)
}

# posterior
post_J <- exp(log_likl + log_prior)
post_J <- post_J / (dl * sum(post_J))

# plot posterior
post_J_plt <- ggplot() +
              labs(title=paste0("Posterior = Gamma(", 0.5+sum(res),",", length(res),")", collapse=""), subtitle="Corresponding to a Jeffrey's prior") +
              geom_line(data = data.frame(mu=mu, post=post_J), aes(x=mu, y=post), color="steelblue", size=1) +
              scale_y_continuous(name = expression(paste("P( ", mu, " | D,M )"))) +
              scale_x_continuous(name = expression(mu)) +
              theme_bw() +
              theme(plot.title=element_text(hjust=0.5), plot.subtitle=element_text(hjust=0.5))
post_J_plt

Evaluate mean, median and variance, both analytically and numerically in R.

mean_num_J <- sum(mu*post_J) * dl
median_num_J <- mu[sum(cumsum(post_J * dl) <= 0.5) + 1]
var_num_J <- sum(mu * mu * post_J * dl) - (mean_num_J * mean_num_J)
mean_an_J <- (0.5 + sum(res)) / length(res)
median_an_J <- qgamma(0.5, shape=0.5+sum(res), rate=length(res))
var_an_J <- (0.5 + sum(res)) / length(res)**2

cat("Mean numerical = ", mean_num_J, "; ", "Mean analytical = ", mean_an_J, "\n", sep="")
Mean numerical = 2.5; Mean analytical = 2.5
cat("Median numerical = ", median_num_J, "; ", "Median analytical = ", median_an_J, "\n", sep="")
Median numerical = 2.432432; Median analytical = 2.433659
cat("Variance numerical = ", var_num_J, "; ", "Variance analytical = ", var_an_J, "\n", sep="")
Variance numerical = 0.5; Variance analytical = 0.5
post_J_plt <- post_J_plt +
              geom_vline(mapping=aes(xintercept = mean_an_J, color="Mean"), linetype="dashed", size=0.5) +
              geom_vline(mapping=aes(xintercept = median_an_J, color="Median"), linetype="dashed", size=0.5) +
              scale_color_manual(values = cbPalette, name="Values")
post_J_plt

Exercise 1c

Evaluate a 95% credibility interval for the results obtained with both priors. Compare the result with that obtained using a normal approximation for the posterior distribution, with the same mean and standard deviation.

# credibility interval for both posteriors
CI_U <- c(qgamma(0.025, shape=1+sum(res), rate=length(res)), qgamma(0.975, shape=1+sum(res), rate=length(res)))
CI_U_gauss <- c(qnorm(0.025, mean=mean_an_U, sd=sqrt(var_an_U)), qnorm(0.975, mean=mean_an_U, sd=sqrt(var_an_U)))
CI_J <- c(qgamma(0.025, shape=0.5+sum(res), rate=length(res)), qgamma(0.975, shape=0.5+sum(res), rate=length(res)))
CI_J_gauss <- c(qnorm(0.025, mean=mean_an_J, sd=sqrt(var_an_J)), qnorm(0.975, mean=mean_an_J, sd=sqrt(var_an_J)))

cat("Credibility interval corresponding to a uniform prior:", CI_U, "\n")
Credibility interval corresponding to a uniform prior: 1.38439 4.192317 
cat("Credibility interval corresponding to a uniform prior with a normal approximation:", CI_U_gauss, "\n")
Credibility interval corresponding to a uniform prior with a normal approximation: 1.18665 4.01335 
cat("Credibility interval corresponding to a Jeffrey's prior:", CI_J, "\n")
Credibility interval corresponding to a Jeffrey's prior: 1.311972 4.064647 
cat("Credibility interval corresponding to a Jeffrey's prior with a normal approximation:", CI_J_gauss, "\n")
Credibility interval corresponding to a Jeffrey's prior with a normal approximation: 1.114096 3.885904 
post_U_plt <- post_U_plt + geom_area(data=data.frame(mu=mu, post=post_U),
                                     aes(x=ifelse(mu>=CI_U[1] & mu<=CI_U[2], mu, NA), y=post, fill="Uniform"),
                                     alpha = 0.2) +
                           scale_fill_manual(values="steelblue", name="95% CI")
post_J_plt <- post_J_plt + geom_area(data=data.frame(mu=mu, post=post_J),
                                     aes(x=ifelse(mu>=CI_J[1] & mu<=CI_J[2], mu, NA), y=post, fill="Jeffrey"),
                                     alpha = 0.2) +
                           scale_fill_manual(values="steelblue", name="95% CI")

grid.arrange(post_U_plt, post_J_plt, nrow=2)

Exercise 2

Given the problem of the lightouse discussed last week, study the case in which both the position along the shore (\(\alpha\)) and the distance out at sea (\(\beta\)) are unknown.

We generate random \(\theta \in \left[ -\dfrac{\pi}{2}, \dfrac{\pi}{2} \right]\) and we calculate the corresponding \(x\) following the relation \[x_k = \alpha + \beta\, \tan{\theta_k}.\]

The prior considered is constant in the rectangle \((\alpha,\beta) \in \left[ -2\, \text{km}, 2\, \text{km} \right] \times \left[ 0\, \text{km}, 5\, \text{km} \right]\) and null elsewhere. The posterior of the problem is thus equivalent to the likelihood in this range and null elsewhere. The log-likelihood used for this problem is \[\log{\mathcal{L}(D\, |\, \alpha,\beta,M)} = \sum_i \log \left[ \dfrac{\beta}{\beta^2 + (x_i - \alpha)^2} \right]\] where \(D=\{x_i\}\) is the set of x-values measured.

# fix true alpha and beta
alpha_true <- 1 #km
beta_true <- 1 #km
alpha_min <- -2 #km
alpha_max <- 2 #km
beta_max <- 5 #km

# define grid
alpha0 <- seq(alpha_min, alpha_max, length.out=1001)
d_alpha <- (alpha_max - alpha_min) / 1000
beta0 <- seq(0, beta_max, length.out=1001)
d_beta <- (beta_max - 0) / 1000
grid0 <- expand_grid(alpha=alpha0, beta=beta0)

# draw samples
n_max <- 1000
lighthouse_samples <- alpha_true + beta_true * tan(runif(n_max, min=-pi/2, max=pi/2))
# function that computes posteriors for the lighthouse problem
compute_posterior_lighthouse <- function(grid_, da_, db_, samples_, marginalize="") {

  # log-posterior
  post_df <- grid_ %>% mutate(log_post = 0)
  for (x_ in samples_) {
    post_df <- post_df %>%
               mutate(log_post = log_post + log(beta/(beta**2 + (x_ - alpha)**2)))
  }
  post_df <- post_df %>% mutate(log_post = log_post - max(log_post))

  # unnormalized posterior
  post_df$post <- exp(post_df$log_post)


  if(marginalize=="alpha") {

    # marginalize over beta and normalize the marginalized posterior
    post_alpha <- post_df %>% group_by(alpha) %>% summarise(post = sum(post, na.rm = TRUE))
    post_alpha$post <- post_alpha$post / (sum(post_alpha$post) * da_)

    return(post_alpha)
  }
  else if (marginalize=="beta") {

    # marginalize over alpha and normalize the marginalized posterior
    post_beta <- post_df %>% group_by(beta) %>% summarise(post = sum(post, na.rm = TRUE))
    post_beta$post <- post_beta$post / (sum(post_beta$post) * db_)

    return(post_beta)
  }
  else {

    # no marginalization
    return(post_df)
  }

}
plt_base <- ggplot() +
            geom_vline(mapping=aes(xintercept = alpha_true), colour="firebrick", linetype="dashed", size=1) +
            scale_x_continuous(name="Alpha") +
            scale_y_continuous(name=expression(paste("P( ", alpha, " | D,M )"))) +
            theme_bw() +
            theme(plot.title=element_text(hjust=0.5))


# plot alpha posterior
grid.arrange(
  plt_base + geom_line(data=compute_posterior_lighthouse(grid0, d_alpha, d_beta, lighthouse_samples[1], marginalize = "alpha"),
                       aes(x=alpha, y=post)) +
             labs(title="Marginalized posterior with 1 sample"),
  plt_base + geom_line(data=compute_posterior_lighthouse(grid0, d_alpha, d_beta, lighthouse_samples[1:2], marginalize = "alpha"),
                       aes(x=alpha, y=post)) +
             labs(title="Marginalized posterior with 2 samples"),
  plt_base + geom_line(data=compute_posterior_lighthouse(grid0, d_alpha, d_beta, lighthouse_samples[1:5], marginalize = "alpha"),
                       aes(x=alpha, y=post)) +
             labs(title="Marginalized posterior with 5 samples"),
  plt_base + geom_line(data=compute_posterior_lighthouse(grid0, d_alpha, d_beta, lighthouse_samples[1:10], marginalize = "alpha"),
                       aes(x=alpha, y=post)) +
             labs(title="Marginalized posterior with 10 samples"),
  plt_base + geom_line(data=compute_posterior_lighthouse(grid0, d_alpha, d_beta, lighthouse_samples[1:20], marginalize = "alpha"),
                       aes(x=alpha, y=post)) +
             labs(title="Marginalized posterior with 20 samples"),
  plt_base + geom_line(data=compute_posterior_lighthouse(grid0, d_alpha, d_beta, lighthouse_samples[1:50], marginalize = "alpha"),
                       aes(x=alpha, y=post)) +
             labs(title="Marginalized posterior with 50 samples"),
  plt_base + geom_line(data=compute_posterior_lighthouse(grid0, d_alpha, d_beta, lighthouse_samples[1:100], marginalize = "alpha"),
                       aes(x=alpha, y=post)) +
             labs(title="Marginalized posterior with 100 samples"),
  nrow=4)

plt_base <- ggplot() +
            geom_vline(mapping=aes(xintercept = beta_true), colour="firebrick", linetype="dashed", size=1) +
            scale_x_continuous(name="Beta") +
            scale_y_continuous(name=expression(paste("P( ", beta, " | D,M )"))) +
            theme_bw() +
            theme(plot.title=element_text(hjust=0.5))


# plot beta posterior
grid.arrange(
  plt_base + geom_line(data=compute_posterior_lighthouse(grid0, d_alpha, d_beta, lighthouse_samples[1], marginalize = "beta"),
                       aes(x=beta, y=post)) +
             labs(title="Marginalized posterior with 1 sample"),
  plt_base + geom_line(data=compute_posterior_lighthouse(grid0, d_alpha, d_beta, lighthouse_samples[1:2], marginalize = "beta"),
                       aes(x=beta, y=post)) +
             labs(title="Marginalized posterior with 2 samples"),
  plt_base + geom_line(data=compute_posterior_lighthouse(grid0, d_alpha, d_beta, lighthouse_samples[1:5], marginalize = "beta"),
                       aes(x=beta, y=post)) +
             labs(title="Marginalized posterior with 5 samples"),
  plt_base + geom_line(data=compute_posterior_lighthouse(grid0, d_alpha, d_beta, lighthouse_samples[1:10], marginalize = "beta"),
                       aes(x=beta, y=post)) +
             labs(title="Marginalized posterior with 10 samples"),
  plt_base + geom_line(data=compute_posterior_lighthouse(grid0, d_alpha, d_beta, lighthouse_samples[1:20], marginalize = "beta"),
                       aes(x=beta, y=post)) +
             labs(title="Marginalized posterior with 20 samples"),
  plt_base + geom_line(data=compute_posterior_lighthouse(grid0, d_alpha, d_beta, lighthouse_samples[1:50], marginalize = "beta"),
                       aes(x=beta, y=post)) +
             labs(title="Marginalized posterior with 50 samples"),
  plt_base + geom_line(data=compute_posterior_lighthouse(grid0, d_alpha, d_beta, lighthouse_samples[1:100], marginalize = "beta"),
                       aes(x=beta, y=post)) +
             labs(title="Marginalized posterior with 100 samples"),
  nrow=4)

plt_base <- ggplot() +
            scale_x_continuous(name="Alpha") +
            scale_y_continuous(name="Beta") +
            theme(plot.title=element_text(hjust=0.5)) +
            theme_bw()

grid.arrange(
  plt_base + geom_contour_filled(data=compute_posterior_lighthouse(grid0, d_alpha, d_beta, lighthouse_samples[1:2]),
                    mapping = aes(x=alpha, y=beta, z=post), show.legend=FALSE) +
             geom_vline(mapping=aes(xintercept = alpha_true), colour="firebrick", linetype="dashed", size=1) +
             geom_hline(mapping=aes(yintercept = beta_true), colour="firebrick", linetype="dashed", size=1) +
             labs(title="Posterior with 2 samples") +
             theme(plot.title=element_text(hjust=0.5)),
  plt_base + geom_contour_filled(data=compute_posterior_lighthouse(grid0, d_alpha, d_beta, lighthouse_samples[1:5]),
                    mapping = aes(x=alpha, y=beta, z=post), show.legend=FALSE) +
             geom_vline(mapping=aes(xintercept = alpha_true), colour="firebrick", linetype="dashed", size=1) +
             geom_hline(mapping=aes(yintercept = beta_true), colour="firebrick", linetype="dashed", size=1) +
             labs(title="Posterior with 5 samples") +
             theme(plot.title=element_text(hjust=0.5)),
  plt_base + geom_contour_filled(data=compute_posterior_lighthouse(grid0, d_alpha, d_beta, lighthouse_samples[1:10]),
                    mapping = aes(x=alpha, y=beta, z=post), show.legend=FALSE) +
             geom_vline(mapping=aes(xintercept = alpha_true), colour="firebrick", linetype="dashed", size=1) +
             geom_hline(mapping=aes(yintercept = beta_true), colour="firebrick", linetype="dashed", size=1) +
             labs(title="Posterior with 10 samples") +
             theme(plot.title=element_text(hjust=0.5)),
  plt_base + geom_contour_filled(data=compute_posterior_lighthouse(grid0, d_alpha, d_beta, lighthouse_samples[1:20]),
                    mapping = aes(x=alpha, y=beta, z=post), show.legend=FALSE) +
             geom_vline(mapping=aes(xintercept = alpha_true), colour="firebrick", linetype="dashed", size=1) +
             geom_hline(mapping=aes(yintercept = beta_true), colour="firebrick", linetype="dashed", size=1) +
             labs(title="Posterior with 20 samples") +
             theme(plot.title=element_text(hjust=0.5)),
  plt_base + geom_contour_filled(data=compute_posterior_lighthouse(grid0, d_alpha, d_beta, lighthouse_samples[1:50]),
                    mapping = aes(x=alpha, y=beta, z=post), show.legend=FALSE) +
             geom_vline(mapping=aes(xintercept = alpha_true), colour="firebrick", linetype="dashed", size=1) +
             geom_hline(mapping=aes(yintercept = beta_true), colour="firebrick", linetype="dashed", size=1) +
             labs(title="Posterior with 50 samples") +
             theme(plot.title=element_text(hjust=0.5)),
  plt_base + geom_contour_filled(data=compute_posterior_lighthouse(grid0, d_alpha, d_beta, lighthouse_samples[1:100]),
                    mapping = aes(x=alpha, y=beta, z=post), show.legend=FALSE) +
             geom_vline(mapping=aes(xintercept = alpha_true), colour="firebrick", linetype="dashed", size=1) +
             geom_hline(mapping=aes(yintercept = beta_true), colour="firebrick", linetype="dashed", size=1) +
             labs(title="Posterior with 100 samples") +
             theme(plot.title=element_text(hjust=0.5)),
  nrow=3)

# find most probables (alpha,beta) for each iteration
max_prob_alpha <- c()
max_prob_beta <- c()
joint_post_df <- grid0 %>% mutate(log_post = 0)

for(x_ in lighthouse_samples[1:100]) {
  joint_post_df <- joint_post_df %>%
                   mutate(log_post = log_post + log(beta/(beta**2 + (x_ - alpha)**2)))
  
  max_indx <- which.max(joint_post_df$log_post)
  max_prob_alpha <- c(max_prob_alpha, joint_post_df[[max_indx, "alpha"]])
  max_prob_beta <- c(max_prob_beta, joint_post_df[[max_indx, "beta"]])
}

# plot succession of most probable values
plt_max_prob_evol <- ggplot(data=data.frame(Alpha=max_prob_alpha, Beta=max_prob_beta),
                            mapping=aes(x=Alpha, y=Beta)) +
                     geom_path() +
                     geom_vline(mapping=aes(xintercept = alpha_true), colour="firebrick", linetype="dashed", size=1) +
                     geom_hline(mapping=aes(yintercept = beta_true), colour="firebrick", linetype="dashed", size=1) +
                     geom_point() +
                     geom_point(aes(x=alpha_true, y=beta_true), colour="firebrick") +
                     geom_text(data=data.frame(alpha=max_prob_alpha[1:10], beta=max_prob_beta[1:10], labels=1:10),
                               mapping=aes(x=alpha+0.05, y=beta+0.05, label = labels)) +
                     labs(title=expression(paste("Evolution of the most probables (", alpha, " , ", beta, ") as a function of number of data samples"))) +
                     theme_bw() +
                     theme(plot.title=element_text(hjust=0.5))
                     

plt_max_prob_evol

As expected, by updating iteratively the posterior with the data, the posterior distribution becomes more and more peaked around the true value of the parameters \(\alpha, \beta\).

Exercise 3

Given the Signal over Background example discussed last week, analyze and discuss the following cases.

The signal is modeled by the following function:

\[ S\,(x\,|\,A,B,x_0,w,\Delta t) = \Delta t \left( A\, e^{-\dfrac{1}{2} \left(\dfrac{x-x_0}{w}\right)^2 } +B \right).\]

The prior considered is constant in the rectangle \((A,B) \in \left[ 0, 5 \right] \times \left[ 0.5, 1.5 \right]\) and null elsewhere. The posterior of the problem is thus equivalent to the likelihood in this range and null elsewhere. The log-likelihood used for this problem is \[\log{\mathcal{L}(D\, |\, A,B,M)} = \sum_i \left[ N_i \ln{S\,(x_i\,|\,A,B)} - S\,(x_i\,|\,A,B) - \ln{(N_i!)} \right]\] where \(D=\{N_i\}\) is the set of counts measured in the positions \(\{x_i\}\).

# (starting) model definitions
x0 <- 0
w <- 1
A_true <- 2
B_true <- 1
dt <- 5
x_grid <- seq(-7*w, 7*w, by=0.5*w)

# define grid for parameters A,B
A_max <- 5
B_min <- 0.5
B_max <- 1.5
A0 <- seq(0, A_max, length.out=1001)
dA <- (A_max - 0) / 1000
B0 <- seq(B_min, B_max, length.out=1001)
dB <- (B_max - B_min) / 1000
grid0 <- expand_grid(A=A0, B=B0)


# signal definition
signal <- function(x, A, B, x0, w, dt) {
  dt * (A * exp(-0.5*((x-x0)/w)**2) + B)
}

# true signal
signal_true_df <- tibble(x=x_grid, Signal=signal(x_grid, A_true, B_true, x0, w, dt))
plt_SB <- ggplot() +
          geom_line(data=signal_true_df, mapping=aes(x=x, y=Signal)) +
          labs(title="Real signal vs measured signal with A/B=2 and w=1") +
          scale_y_continuous(name = expression(paste("Signal (x | A, B, ", x[0], ", w, ", Delta, "t, M)"))) +
          theme_bw() +
          theme(plot.title=element_text(hjust=0.5))
          

# sample signals
signal_samples <- rpois(length(x_grid), signal_true_df$Signal)
signal_samples_df <- tibble(x=x_grid, N=signal_samples)
plt_SB <- plt_SB +
          geom_col(data=signal_samples_df, mapping=aes(x=x, y=N), alpha=0.3)

plt_SB

# function that computes the posterior for the Signal/Background problem,
# it computes the posterior for different values of the parameters
# w, A_true, B_true, x0, dt
compute_posterior_SB <- function(x0=0, w=1, A_true=2, B_true=1, dt=5,
                                 A_max=5, B_min=0.5, B_max=1.5,
                                 marginalize="") {
  
  # reproducibility
  set.seed(12345)
  
  # define grid
  grid_x_ <- seq(-7*w, 7*w, by=0.5*w)
  grid_ <- expand_grid(A=seq(0, A_max, length.out=1001), B=seq(B_min, B_max, length.out=1001))
  dA_ <- (A_max - 0) / 1000
  dB_ <- (B_max - B_min) / 1000
  
  
  # true signal
  signal_true <- signal(grid_x_, A_true, B_true, x0, w, dt)
  
  # sample signals
  samples_ <- rpois(n=length(grid_x_), lambda=signal_true)
  
  
  
  # log-posterior
  post_df <- grid_ %>% mutate(log_post = 0)
  for (i in 1:length(samples_)) {
    post_df <- post_df %>%
               mutate(log_post = log_post + dpois(x=samples_[i], lambda = signal(grid_x_[i], A, B, x0=x0, w=w, dt=dt), log=TRUE))
  }
  post_df <- post_df %>% mutate(log_post = log_post - max(log_post))

  # unnormalized posterior
  post_df$Posterior <- exp(post_df$log_post)
  
  
  
  if(marginalize=="A") {

    # marginalize over B and normalize the marginalized posterior
    post_A <- post_df %>% group_by(A) %>% summarise(Posterior = sum(Posterior, na.rm = TRUE))
    post_A$Posterior <- post_A$Posterior / (sum(post_A$Posterior) * dA_)

    return(post_A)
  }
  else if (marginalize=="B") {

    # marginalize over A and normalize the marginalized posterior
    post_B <- post_df %>% group_by(B) %>% summarise(Posterior = sum(Posterior, na.rm = TRUE))
    post_B$Posterior <- post_B$Posterior / (sum(post_B$Posterior) * dB_)

    return(post_B)
  }
  else {

    # no marginalization
    return(post_df)
  }
  
}

Exercise 3a

Vary the sampling resolution used to generate the data, keeping the same sampling range. Change the resolution w = {0.1, 0.25, 1, 2, 3} and check the effect on the results.

plot_signal <- function(x0=0, w=1, A_true=2, B_true=1, dt=5,
                        A_max=5, B_min=0.5, B_max=1.5, xlim=c(-8*w,8*w)) {
  
  # reproducibility
  #set.seed(12345)
  
  # define grid
  grid_x_ <- seq(-7*w, 7*w, by=0.5*w)
  
  # true signal
  signal_true <- signal(grid_x_, A_true, B_true, x0, w, dt)
  signal_true_df <- tibble(x=grid_x_, Signal=signal_true)
  
  # sample signals
  signal_samples <- rpois(length(grid_x_), signal_true_df$Signal)
  signal_samples_df <- tibble(x=grid_x_, N=signal_samples)
  
  
  
  # plot
  plt <- ggplot() +
         geom_line(data=signal_true_df, mapping=aes(x=x, y=Signal)) +
         geom_col(data=signal_samples_df, mapping=aes(x=x, y=N), alpha=0.3) +
         labs(title=paste0("Real signal vs measured signal with A/B=", A_true/B_true, " and w=", w, collapse = "")) +
         scale_x_continuous(limits=xlim) +
         scale_y_continuous(name = expression(paste("Signal (x | A, B, ", x[0], ", w, ", Delta, "t, M)"))) +
         theme_bw() +
         theme(plot.title=element_text(hjust=0.5))
  
  return(plt)
}
# plot real signals vs measured signal as a function of w
grid.arrange(
plot_signal(w=0.1, A_true=2, B_true=1, xlim=c(-22,22)),
plot_signal(w=0.25, A_true=2, B_true=1, xlim=c(-22,22)),
plot_signal(w=1, A_true=2, B_true=1, xlim=c(-22,22)),
plot_signal(w=2, A_true=2, B_true=1, xlim=c(-22,22)),
plot_signal(w=3, A_true=2, B_true=1, xlim=c(-22,22)),
nrow=3)

As it is possible to see from the plots above, the change of the scale parameter \(w\) if the sampling range remains fixed affects the spatial width of the signal but not the parameters \(A,B\). The plots below show the independence of \(A,B\) on \(w\) when the sampling range is fixed. This effect occurs because the signal depends only on the ratio \(x/w\) (\(x_0=0\)) and not singularly on the two variables. Since the x-grid is proportional to \(w\), the signal generated are exactly the same. To see some changes in the plots we could fix the spatial (x-)width of the signal and vary the parameter \(w\) in order to vary the number of channels that can collect the signal.

# plot two posteriors as an example of invariance w.r.t. w parameter
grid.arrange(
  ggplot() + geom_contour_filled(data=compute_posterior_SB(w=0.1), mapping = aes(x=A, y=B, z=Posterior), show.legend=FALSE) +
             labs(title=paste("Posterior with A/B=2 and w=0.1")) +
             theme_bw() +
             theme(plot.title=element_text(hjust=0.5)),
  ggplot() + geom_contour_filled(data=compute_posterior_SB(w=3), mapping = aes(x=A, y=B, z=Posterior), show.legend=FALSE) +
             labs(title=paste("Posterior with A/B=2 and w=3")) +
             theme_bw() +
             theme(plot.title=element_text(hjust=0.5)),
  nrow=1)

Exercise 3b

Change the ratio A/B used to simulate the data (keeping both positive in accordance with the prior). Check the effect on the results.

We investigate the ratios \(A/B = \{ 0.25, 0.5, 1, 2, 4\}\) by fixing \(B=1\) and choosing \(A= \{ 0.25, 0.5, 1, 2, 4\}\).

# plot real signals vs measured signal as a function of A/B
grid.arrange(
plot_signal(w=1, A_true=0.25, B_true=1),
plot_signal(w=1, A_true=0.5, B_true=1),
plot_signal(w=1, A_true=1, B_true=1),
plot_signal(w=1, A_true=2, B_true=1),
plot_signal(w=1, A_true=4, B_true=1),
nrow=3)

# plot A posterior
grid.arrange(
  ggplot() + geom_line(data=compute_posterior_SB(A_true=0.25, B_true=1, marginalize = "A"),
                       aes(x=A, y=Posterior)) +
             geom_vline(mapping=aes(xintercept = 0.25), colour="firebrick", linetype="dashed", size=1) +
             labs(title="Marginalized posterior with A/B=0.25 and w=1") +
             scale_y_continuous(name="P( A | D,M )") +
             theme_bw() +
             theme(plot.title=element_text(hjust=0.5)),
  ggplot() + geom_line(data=compute_posterior_SB(A_true=0.5, B_true=1, marginalize = "A"),
                       aes(x=A, y=Posterior)) +
             geom_vline(mapping=aes(xintercept = 0.5), colour="firebrick", linetype="dashed", size=1) +
             labs(title="Marginalized posterior with A/B=0.5 and w=1") +
             scale_y_continuous(name="P( A | D,M )") +
             theme_bw() +
             theme(plot.title=element_text(hjust=0.5)),
  ggplot() + geom_line(data=compute_posterior_SB(A_true=1, B_true=1, marginalize = "A"),
                       aes(x=A, y=Posterior)) +
             geom_vline(mapping=aes(xintercept = 1), colour="firebrick", linetype="dashed", size=1) +
             labs(title="Marginalized posterior with A/B=1 and w=1") +
             scale_y_continuous(name="P( A | D,M )") +
             theme_bw() +
             theme(plot.title=element_text(hjust=0.5)),
  ggplot() + geom_line(data=compute_posterior_SB(A_true=2, B_true=1, marginalize = "A"),
                       aes(x=A, y=Posterior)) +
             geom_vline(mapping=aes(xintercept = 2), colour="firebrick", linetype="dashed", size=1) +
             labs(title="Marginalized posterior with A/B=2 and w=1") +
             scale_y_continuous(name="P( A | D,M )") +
             theme_bw() +
             theme(plot.title=element_text(hjust=0.5)),
  ggplot() + geom_line(data=compute_posterior_SB(A_true=4, B_true=1, marginalize = "A"),
                       aes(x=A, y=Posterior)) +
             geom_vline(mapping=aes(xintercept = 4), colour="firebrick", linetype="dashed", size=1) +
             labs(title="Marginalized posterior with A/B=4 and w=1") +
             scale_y_continuous(name="P( A | D,M )") +
             theme_bw() +
             theme(plot.title=element_text(hjust=0.5)),
  nrow=3)

# plot B posterior
grid.arrange(
  ggplot() + geom_line(data=compute_posterior_SB(A_true=0.25, B_true=1, marginalize = "B"),
                       aes(x=B, y=Posterior)) +
             geom_vline(mapping=aes(xintercept = 1), colour="firebrick", linetype="dashed", size=1) +
             labs(title="Marginalized posterior with A/B=0.25 and w=1") +
             scale_y_continuous(name="P( B | D,M )") +
             theme_bw() +
             theme(plot.title=element_text(hjust=0.5)),
  ggplot() + geom_line(data=compute_posterior_SB(A_true=0.5, B_true=1, marginalize = "B"),
                       aes(x=B, y=Posterior)) +
             geom_vline(mapping=aes(xintercept = 1), colour="firebrick", linetype="dashed", size=1) +
             labs(title="Marginalized posterior with A/B=0.5 and w=1") +
             scale_y_continuous(name="P( B | D,M )") +
             theme_bw() +
             theme(plot.title=element_text(hjust=0.5)),
  ggplot() + geom_line(data=compute_posterior_SB(A_true=1, B_true=1, marginalize = "B"),
                       aes(x=B, y=Posterior)) +
             geom_vline(mapping=aes(xintercept = 1), colour="firebrick", linetype="dashed", size=1) +
             labs(title="Marginalized posterior with A/B=1 and w=1") +
             scale_y_continuous(name="P( B | D,M )") +
             theme_bw() +
             theme(plot.title=element_text(hjust=0.5)),
  ggplot() + geom_line(data=compute_posterior_SB(A_true=2, B_true=1, marginalize = "B"),
                       aes(x=B, y=Posterior)) +
             geom_vline(mapping=aes(xintercept = 1), colour="firebrick", linetype="dashed", size=1) +
             labs(title="Marginalized posterior with A/B=2 and w=1") +
             scale_y_continuous(name="P( B | D,M )") +
             theme_bw() +
             theme(plot.title=element_text(hjust=0.5)),
  ggplot() + geom_line(data=compute_posterior_SB(A_true=4, B_true=1, marginalize = "B"),
                       aes(x=B, y=Posterior)) +
             geom_vline(mapping=aes(xintercept = 1), colour="firebrick", linetype="dashed", size=1) +
             labs(title="Marginalized posterior with A/B=4 and w=1") +
             scale_y_continuous(name="P( B | D,M )") +
             theme_bw() +
             theme(plot.title=element_text(hjust=0.5)),
  nrow=3)

plt_base <- ggplot() +
            theme_bw() +
            theme(plot.title=element_text(hjust=0.5))

grid.arrange(
  plt_base + geom_contour_filled(data=compute_posterior_SB(A_true=0.25, B_true=1),
                                 mapping = aes(x=A, y=B, z=Posterior), show.legend=FALSE) +
             geom_vline(mapping=aes(xintercept = 0.25), colour="firebrick", linetype="dashed", size=1) +
             geom_hline(mapping=aes(yintercept = 1), colour="firebrick", linetype="dashed", size=1) +
             labs(title="Posterior with A/B=0.25 and w=1"),
  plt_base + geom_contour_filled(data=compute_posterior_SB(A_true=0.5, B_true=1),
                                 mapping = aes(x=A, y=B, z=Posterior), show.legend=FALSE) +
             geom_vline(mapping=aes(xintercept = 0.5), colour="firebrick", linetype="dashed", size=1) +
             geom_hline(mapping=aes(yintercept = 1), colour="firebrick", linetype="dashed", size=1) +
             labs(title="Posterior with A/B=0.5 and w=1"),
  plt_base + geom_contour_filled(data=compute_posterior_SB(A_true=1, B_true=1),
                                 mapping = aes(x=A, y=B, z=Posterior), show.legend=FALSE) +
             geom_vline(mapping=aes(xintercept = 1), colour="firebrick", linetype="dashed", size=1) +
             geom_hline(mapping=aes(yintercept = 1), colour="firebrick", linetype="dashed", size=1) +
             labs(title="Posterior with A/B=1 and w=1"),
  plt_base + geom_contour_filled(data=compute_posterior_SB(A_true=2, B_true=1),
                                 mapping = aes(x=A, y=B, z=Posterior), show.legend=FALSE) +
             geom_vline(mapping=aes(xintercept = 2), colour="firebrick", linetype="dashed", size=1) +
             geom_hline(mapping=aes(yintercept = 1), colour="firebrick", linetype="dashed", size=1) +
             labs(title="Posterior with A/B=2 and w=1"),
  plt_base + geom_contour_filled(data=compute_posterior_SB(A_true=4, B_true=1),
                                 mapping = aes(x=A, y=B, z=Posterior), show.legend=FALSE) +
             geom_vline(mapping=aes(xintercept = 4), colour="firebrick", linetype="dashed", size=1) +
             geom_hline(mapping=aes(yintercept = 1), colour="firebrick", linetype="dashed", size=1) +
             labs(title="Posterior with A/B=4 and w=1"),
  nrow=3)

LS0tCnRpdGxlOiAiTGFib3JhdG9yeSBTZXNzaW9uIC0gQXByaWwgMjgsIDIwMjIiCm91dHB1dDogaHRtbF9ub3RlYm9vawplZGl0b3Jfb3B0aW9uczoKICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lCi0tLQoKIyBQYW9sbyBaaW5lc2kgMjA1MzA2MgoKYGBge3J9CnNldC5zZWVkKDEyMzQ1KQoKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoZ3JpZEV4dHJhKQoKY2JQYWxldHRlIDwtIGMoIiMwMDAwMDAiLCAiI0U2OUYwMCIsICIjNTZCNEU5IiwgIiMwMDlFNzMiLCAiI0YwRTQ0MiIsICIjMDA3MkIyIiwgIiNENTVFMDAiLCAiI0NDNzlBNyIpCmBgYAoKIyMgRXhlcmNpc2UgMQoKVGhlIG51bWJlciBvZiBwYXJ0aWNsZXMgZW1pdHRlZCBieSBhIHJhZGlvYWN0aXZlIHNvdXJjZSBkdXJpbmcgYSBmaXhlZCBpbnRlcnZhbCBvZiB0aW1lICjiiIZ0ID0gMTAgcykgZm9sbG93cyBhIFBvaXNzb24gZGlzdHJpYnV0aW9uIG9uIHRoZSBwYXJhbWV0ZXIgJFxtdSQuIFRoZSBudW1iZXIgb2YgcGFydGljbGVzIG9ic2VydmVkIGR1cmluZyBjb25zZWN1dGl2ZSB0aW1lIGludGVydmFscyBpczoKJCRceyA0LCAxLCAzLCAxLCAzIFx9JCQKCldlIHVzZSBwcmlvcnMgdGhhdCBhcmUgY29uanVnYXRlIHRvIHRoZSBsaWtlbGlob29kLiBGb3IgYSBQb2lzc29uIHByb2Nlc3MgdGhlIGNvbmp1Z2F0ZSBwcmlvciBpcyBhIEdhbW1hIGRpc3RyaWJ1dGlvbiwgd2hpY2ggUERGIGlzICRcdGV4dHtHYW1tYX0gXGxlZnQoeVwsfFwsXGFscGhhLFxsYW1iZGEgXHJpZ2h0KSA9IFxkZnJhY3tcbGFtYmRhXntcYWxwaGF9fXtcR2FtbWF7KFxhbHBoYSl9fVwsIHlee1xhbHBoYS0xfVwsIGVeey1cbGFtYmRhXCwgeX0kLiBJZiB0aGUgcHJpb3IgaGFzIHRoZSBmb3JtICRcdGV4dHtHYW1tYX0gXGxlZnQoXGFscGhhLFxsYW1iZGEgXHJpZ2h0KSQgYW5kIHdlIGhhdmUgJG4kIG9ic2VydmF0aW9ucyB3aXRoIHJlc3VsdHMgJFx7eV9pXH0kLCB0aGUgcG9zdGVyaW9yIGhhcyB0aGUgZm9ybSAkXHRleHR7R2FtbWF9XGxlZnQoXGFscGhhICsgXHN1bV9pIHlfaSwgXCxcbGFtYmRhICsgbiBccmlnaHQpJC4gVGhlIG1lYW4gb2YgYSAkXHRleHR7R2FtbWF9IFxsZWZ0KFxhbHBoYSxcbGFtYmRhIFxyaWdodCkkIGRpc3RyaWJ1dGlvbiBpcyAkXGRmcmFje1xhbHBoYX17XGxhbWJkYX0kIGFuZCB0aGUgdmFyaWFuY2UgaXMgJFxkZnJhY3tcYWxwaGF9e1xsYW1iZGFeMn0kCgoKYGBge3J9CnJlcyA8LSBjKDQsIDEsIDMsIDEsIDMpCm11IDwtIHNlcSgwLCAxMCwgbGVuZ3RoLm91dD0xMDAwKQpOX2RsIDwtIGxlbmd0aChtdSkgLSAxCmRsIDwtIChtYXgobXUpIC0gbWluKG11KSkgLyBOX2RsCmBgYAoKIyMjIEV4ZXJjaXNlIDFhCgpTdXBwb3NlIGEgdW5pZm9ybSBwcmlvciBkaXN0cmlidXRpb24gZm9yIHRoZSBwYXJhbWV0ZXIgJFxtdSQuCkRldGVybWluZSBhbmQgZHJhdyB0aGUgcG9zdGVyaW9yIGRpc3RyaWJ1dGlvbiBmb3IgJFxtdSQsIGdpdmVuIHRoZSBkYXRhICREPVx7eV9pXH0kLgoKQSB1bmlmb3JtIHByaW9yIGhhcyB0aGUgZm9ybSAkXHRleHR7R2FtbWF9IFxsZWZ0KDEsMCBccmlnaHQpJCwgc28gdGhlIHBvc3RlcmlvciBoYXMgdGhlIGZvcm0gJFx0ZXh0e0dhbW1hfSBcbGVmdCgxK1xzdW1faSB5X2ksIFwsMCArIG4gXHJpZ2h0KSQuCgpgYGB7cn0KIyBwcmlvcgpsb2dfcHJpb3IgPC0gaWZlbHNlKG11Pj0wLCAwLCAtSW5mKQoKIyBsaWtlbGlob29kCmxvZ19saWtsIDwtIDAKZm9yIChyXyBpbiByZXMpIHsKICBsb2dfbGlrbCA8LSBsb2dfbGlrbCArIGRwb2lzKHg9cl8sIGxhbWJkYT1tdSwgbG9nPVRSVUUpCn0KCiMgcG9zdGVyaW9yCnBvc3RfVSA8LSBleHAobG9nX2xpa2wgKyBsb2dfcHJpb3IpCnBvc3RfVSA8LSBwb3N0X1UgLyAoZGwgKiBzdW0ocG9zdF9VKSkKCiMgcGxvdCBwb3N0ZXJpb3IKcG9zdF9VX3BsdCA8LSBnZ3Bsb3QoKSArCiAgICAgICAgICAgICAgbGFicyh0aXRsZT1wYXN0ZTAoIlBvc3RlcmlvciA9IEdhbW1hKCIsIDErc3VtKHJlcyksIiwiLCBsZW5ndGgocmVzKSwiKSIsIGNvbGxhcHNlPSIiKSwgc3VidGl0bGU9IkNvcnJlc3BvbmRpbmcgdG8gYSB1bmlmb3JtIHByaW9yIikgKwogICAgICAgICAgICAgIGdlb21fbGluZShkYXRhID0gZGF0YS5mcmFtZShtdT1tdSwgcG9zdD1wb3N0X1UpLCBhZXMoeD1tdSwgeT1wb3N0KSwgY29sb3I9InN0ZWVsYmx1ZSIsIHNpemU9MSkgKwogICAgICAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhuYW1lID0gZXhwcmVzc2lvbihwYXN0ZSgiUCggIiwgbXUsICIgfCBELE0gKSIpKSkgKwogICAgICAgICAgICAgIHNjYWxlX3hfY29udGludW91cyhuYW1lID0gZXhwcmVzc2lvbihtdSkpICsKICAgICAgICAgICAgICB0aGVtZV9idygpICsKICAgICAgICAgICAgICB0aGVtZShwbG90LnRpdGxlPWVsZW1lbnRfdGV4dChoanVzdD0wLjUpLCBwbG90LnN1YnRpdGxlPWVsZW1lbnRfdGV4dChoanVzdD0wLjUpKQpwb3N0X1VfcGx0CmBgYAoKCgpFdmFsdWF0ZSBtZWFuLCBtZWRpYW4gYW5kIHZhcmlhbmNlLCBib3RoIGFuYWx5dGljYWxseSBhbmQgbnVtZXJpY2FsbHkgaW4gUi4KYGBge3J9Cm1lYW5fbnVtX1UgPC0gc3VtKG11KnBvc3RfVSkgKiBkbAptZWRpYW5fbnVtX1UgPC0gbXVbc3VtKGN1bXN1bShwb3N0X1UgKiBkbCkgPD0gMC41KSArIDFdCnZhcl9udW1fVSA8LSBzdW0obXUgKiBtdSAqIHBvc3RfVSAqIGRsKSAtIChtZWFuX251bV9VICogbWVhbl9udW1fVSkKbWVhbl9hbl9VIDwtICgxICsgc3VtKHJlcykpIC8gbGVuZ3RoKHJlcykKbWVkaWFuX2FuX1UgPC0gcWdhbW1hKDAuNSwgc2hhcGU9MStzdW0ocmVzKSwgcmF0ZT1sZW5ndGgocmVzKSkKdmFyX2FuX1UgPC0gKDEgKyBzdW0ocmVzKSkgLyBsZW5ndGgocmVzKSoqMgoKY2F0KCJNZWFuIG51bWVyaWNhbCA9ICIsIG1lYW5fbnVtX1UsICI7ICIsICJNZWFuIGFuYWx5dGljYWwgPSAiLCBtZWFuX2FuX1UsICJcbiIsIHNlcD0iIikKY2F0KCJNZWRpYW4gbnVtZXJpY2FsID0gIiwgbWVkaWFuX251bV9VLCAiOyAiLCAiTWVkaWFuIGFuYWx5dGljYWwgPSAiLCBtZWRpYW5fYW5fVSwgIlxuIiwgc2VwPSIiKQpjYXQoIlZhcmlhbmNlIG51bWVyaWNhbCA9ICIsIHZhcl9udW1fVSwgIjsgIiwgIlZhcmlhbmNlIGFuYWx5dGljYWwgPSAiLCB2YXJfYW5fVSwgIlxuIiwgc2VwPSIiKQpgYGAKCmBgYHtyfQpwb3N0X1VfcGx0IDwtIHBvc3RfVV9wbHQgKwogICAgICAgICAgICAgIGdlb21fdmxpbmUobWFwcGluZz1hZXMoeGludGVyY2VwdCA9IG1lYW5fYW5fVSwgY29sb3I9Ik1lYW4iKSwgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MC41KSArCiAgICAgICAgICAgICAgZ2VvbV92bGluZShtYXBwaW5nPWFlcyh4aW50ZXJjZXB0ID0gbWVkaWFuX2FuX1UsIGNvbG9yPSJNZWRpYW4iKSwgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MC41KSArCiAgICAgICAgICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNiUGFsZXR0ZSwgbmFtZT0iVmFsdWVzIikKcG9zdF9VX3BsdApgYGAKCgoKIyMjIEV4ZXJjaXNlIDFiCgpTdXBwb3NlIGEgSmVmZnJleeKAmXMgcHJpb3IgZm9yIHRoZSBwYXJhbWV0ZXIgJFxtdSQuCkRldGVybWluZSBhbmQgZHJhdyB0aGUgcG9zdGVyaW9yIGRpc3RyaWJ1dGlvbiBmb3IgJFxtdSQsIGdpdmVuIHRoZSBkYXRhLgoKQSBKZWZmcmV5J3MgcHJpb3IgaGFzIHRoZSBmb3JtICRcdGV4dHtHYW1tYX0gXGxlZnQoXGRmcmFjezF9ezJ9LDAgXHJpZ2h0KSQsIHNvIHRoZSBwb3N0ZXJpb3IgaGFzIHRoZSBmb3JtICRcdGV4dHtHYW1tYX0gXGxlZnQoXGRmcmFjezF9ezJ9K1xzdW1faSB5X2ksIFwsMCArIG4gXHJpZ2h0KSQuCgpgYGB7cn0KIyBwcmlvcgpsb2dfcHJpb3IgPC0gaWZlbHNlKG11ID4gMCwgLTAuNSpsb2cobXUpLCAtSW5mKQoKIyBsaWtlbGlob29kCmxvZ19saWtsIDwtIDAKZm9yIChyXyBpbiByZXMpIHsKICBsb2dfbGlrbCA8LSBsb2dfbGlrbCArIGRwb2lzKHg9cl8sIGxhbWJkYT1tdSwgbG9nPVRSVUUpCn0KCiMgcG9zdGVyaW9yCnBvc3RfSiA8LSBleHAobG9nX2xpa2wgKyBsb2dfcHJpb3IpCnBvc3RfSiA8LSBwb3N0X0ogLyAoZGwgKiBzdW0ocG9zdF9KKSkKCiMgcGxvdCBwb3N0ZXJpb3IKcG9zdF9KX3BsdCA8LSBnZ3Bsb3QoKSArCiAgICAgICAgICAgICAgbGFicyh0aXRsZT1wYXN0ZTAoIlBvc3RlcmlvciA9IEdhbW1hKCIsIDAuNStzdW0ocmVzKSwiLCIsIGxlbmd0aChyZXMpLCIpIiwgY29sbGFwc2U9IiIpLCBzdWJ0aXRsZT0iQ29ycmVzcG9uZGluZyB0byBhIEplZmZyZXkncyBwcmlvciIpICsKICAgICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IGRhdGEuZnJhbWUobXU9bXUsIHBvc3Q9cG9zdF9KKSwgYWVzKHg9bXUsIHk9cG9zdCksIGNvbG9yPSJzdGVlbGJsdWUiLCBzaXplPTEpICsKICAgICAgICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMobmFtZSA9IGV4cHJlc3Npb24ocGFzdGUoIlAoICIsIG11LCAiIHwgRCxNICkiKSkpICsKICAgICAgICAgICAgICBzY2FsZV94X2NvbnRpbnVvdXMobmFtZSA9IGV4cHJlc3Npb24obXUpKSArCiAgICAgICAgICAgICAgdGhlbWVfYncoKSArCiAgICAgICAgICAgICAgdGhlbWUocGxvdC50aXRsZT1lbGVtZW50X3RleHQoaGp1c3Q9MC41KSwgcGxvdC5zdWJ0aXRsZT1lbGVtZW50X3RleHQoaGp1c3Q9MC41KSkKcG9zdF9KX3BsdApgYGAKCgpFdmFsdWF0ZSBtZWFuLCBtZWRpYW4gYW5kIHZhcmlhbmNlLCBib3RoIGFuYWx5dGljYWxseSBhbmQgbnVtZXJpY2FsbHkgaW4gUi4KYGBge3J9Cm1lYW5fbnVtX0ogPC0gc3VtKG11KnBvc3RfSikgKiBkbAptZWRpYW5fbnVtX0ogPC0gbXVbc3VtKGN1bXN1bShwb3N0X0ogKiBkbCkgPD0gMC41KSArIDFdCnZhcl9udW1fSiA8LSBzdW0obXUgKiBtdSAqIHBvc3RfSiAqIGRsKSAtIChtZWFuX251bV9KICogbWVhbl9udW1fSikKbWVhbl9hbl9KIDwtICgwLjUgKyBzdW0ocmVzKSkgLyBsZW5ndGgocmVzKQptZWRpYW5fYW5fSiA8LSBxZ2FtbWEoMC41LCBzaGFwZT0wLjUrc3VtKHJlcyksIHJhdGU9bGVuZ3RoKHJlcykpCnZhcl9hbl9KIDwtICgwLjUgKyBzdW0ocmVzKSkgLyBsZW5ndGgocmVzKSoqMgoKY2F0KCJNZWFuIG51bWVyaWNhbCA9ICIsIG1lYW5fbnVtX0osICI7ICIsICJNZWFuIGFuYWx5dGljYWwgPSAiLCBtZWFuX2FuX0osICJcbiIsIHNlcD0iIikKY2F0KCJNZWRpYW4gbnVtZXJpY2FsID0gIiwgbWVkaWFuX251bV9KLCAiOyAiLCAiTWVkaWFuIGFuYWx5dGljYWwgPSAiLCBtZWRpYW5fYW5fSiwgIlxuIiwgc2VwPSIiKQpjYXQoIlZhcmlhbmNlIG51bWVyaWNhbCA9ICIsIHZhcl9udW1fSiwgIjsgIiwgIlZhcmlhbmNlIGFuYWx5dGljYWwgPSAiLCB2YXJfYW5fSiwgIlxuIiwgc2VwPSIiKQpgYGAKCgpgYGB7cn0KcG9zdF9KX3BsdCA8LSBwb3N0X0pfcGx0ICsKICAgICAgICAgICAgICBnZW9tX3ZsaW5lKG1hcHBpbmc9YWVzKHhpbnRlcmNlcHQgPSBtZWFuX2FuX0osIGNvbG9yPSJNZWFuIiksIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTAuNSkgKwogICAgICAgICAgICAgIGdlb21fdmxpbmUobWFwcGluZz1hZXMoeGludGVyY2VwdCA9IG1lZGlhbl9hbl9KLCBjb2xvcj0iTWVkaWFuIiksIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTAuNSkgKwogICAgICAgICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjYlBhbGV0dGUsIG5hbWU9IlZhbHVlcyIpCnBvc3RfSl9wbHQKYGBgCgojIyMgRXhlcmNpc2UgMWMKRXZhbHVhdGUgYSA5NSUgY3JlZGliaWxpdHkgaW50ZXJ2YWwgZm9yIHRoZSByZXN1bHRzIG9idGFpbmVkIHdpdGggYm90aCBwcmlvcnMuIENvbXBhcmUgdGhlIHJlc3VsdCB3aXRoIHRoYXQgb2J0YWluZWQgdXNpbmcgYSBub3JtYWwgYXBwcm94aW1hdGlvbiBmb3IgdGhlIHBvc3RlcmlvciBkaXN0cmlidXRpb24sIHdpdGggdGhlIHNhbWUgbWVhbiBhbmQgc3RhbmRhcmQgZGV2aWF0aW9uLgoKYGBge3J9CiMgY3JlZGliaWxpdHkgaW50ZXJ2YWwgZm9yIGJvdGggcG9zdGVyaW9ycwpDSV9VIDwtIGMocWdhbW1hKDAuMDI1LCBzaGFwZT0xK3N1bShyZXMpLCByYXRlPWxlbmd0aChyZXMpKSwgcWdhbW1hKDAuOTc1LCBzaGFwZT0xK3N1bShyZXMpLCByYXRlPWxlbmd0aChyZXMpKSkKQ0lfVV9nYXVzcyA8LSBjKHFub3JtKDAuMDI1LCBtZWFuPW1lYW5fYW5fVSwgc2Q9c3FydCh2YXJfYW5fVSkpLCBxbm9ybSgwLjk3NSwgbWVhbj1tZWFuX2FuX1UsIHNkPXNxcnQodmFyX2FuX1UpKSkKQ0lfSiA8LSBjKHFnYW1tYSgwLjAyNSwgc2hhcGU9MC41K3N1bShyZXMpLCByYXRlPWxlbmd0aChyZXMpKSwgcWdhbW1hKDAuOTc1LCBzaGFwZT0wLjUrc3VtKHJlcyksIHJhdGU9bGVuZ3RoKHJlcykpKQpDSV9KX2dhdXNzIDwtIGMocW5vcm0oMC4wMjUsIG1lYW49bWVhbl9hbl9KLCBzZD1zcXJ0KHZhcl9hbl9KKSksIHFub3JtKDAuOTc1LCBtZWFuPW1lYW5fYW5fSiwgc2Q9c3FydCh2YXJfYW5fSikpKQoKY2F0KCJDcmVkaWJpbGl0eSBpbnRlcnZhbCBjb3JyZXNwb25kaW5nIHRvIGEgdW5pZm9ybSBwcmlvcjoiLCBDSV9VLCAiXG4iKQpjYXQoIkNyZWRpYmlsaXR5IGludGVydmFsIGNvcnJlc3BvbmRpbmcgdG8gYSB1bmlmb3JtIHByaW9yIHdpdGggYSBub3JtYWwgYXBwcm94aW1hdGlvbjoiLCBDSV9VX2dhdXNzLCAiXG4iKQpjYXQoIkNyZWRpYmlsaXR5IGludGVydmFsIGNvcnJlc3BvbmRpbmcgdG8gYSBKZWZmcmV5J3MgcHJpb3I6IiwgQ0lfSiwgIlxuIikKY2F0KCJDcmVkaWJpbGl0eSBpbnRlcnZhbCBjb3JyZXNwb25kaW5nIHRvIGEgSmVmZnJleSdzIHByaW9yIHdpdGggYSBub3JtYWwgYXBwcm94aW1hdGlvbjoiLCBDSV9KX2dhdXNzLCAiXG4iKQpgYGAKCgpgYGB7ciwgd2FybmluZz1GQUxTRSwgZmlnLndpZHRoPTUsIGZpZy5oZWlnaHQ9M30KcG9zdF9VX3BsdCA8LSBwb3N0X1VfcGx0ICsgZ2VvbV9hcmVhKGRhdGE9ZGF0YS5mcmFtZShtdT1tdSwgcG9zdD1wb3N0X1UpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWVzKHg9aWZlbHNlKG11Pj1DSV9VWzFdICYgbXU8PUNJX1VbMl0sIG11LCBOQSksIHk9cG9zdCwgZmlsbD0iVW5pZm9ybSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjIpICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPSJzdGVlbGJsdWUiLCBuYW1lPSI5NSUgQ0kiKQpwb3N0X0pfcGx0IDwtIHBvc3RfSl9wbHQgKyBnZW9tX2FyZWEoZGF0YT1kYXRhLmZyYW1lKG11PW11LCBwb3N0PXBvc3RfSiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZXMoeD1pZmVsc2UobXU+PUNJX0pbMV0gJiBtdTw9Q0lfSlsyXSwgbXUsIE5BKSwgeT1wb3N0LCBmaWxsPSJKZWZmcmV5IiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMikgKwogICAgICAgICAgICAgICAgICAgICAgICAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9InN0ZWVsYmx1ZSIsIG5hbWU9Ijk1JSBDSSIpCgpncmlkLmFycmFuZ2UocG9zdF9VX3BsdCwgcG9zdF9KX3BsdCwgbnJvdz0yKQpgYGAKCgojIyBFeGVyY2lzZSAyCgpHaXZlbiB0aGUgcHJvYmxlbSBvZiB0aGUgbGlnaHRvdXNlIGRpc2N1c3NlZCBsYXN0IHdlZWssIHN0dWR5IHRoZSBjYXNlIGluIHdoaWNoIGJvdGggdGhlIHBvc2l0aW9uIGFsb25nIHRoZSBzaG9yZSAoJFxhbHBoYSQpIGFuZCB0aGUgZGlzdGFuY2Ugb3V0IGF0IHNlYSAoJFxiZXRhJCkgYXJlIHVua25vd24uCgpXZSBnZW5lcmF0ZSByYW5kb20gJFx0aGV0YSBcaW4gXGxlZnRbIC1cZGZyYWN7XHBpfXsyfSwgXGRmcmFje1xwaX17Mn0gXHJpZ2h0XSQgYW5kIHdlIGNhbGN1bGF0ZSB0aGUgY29ycmVzcG9uZGluZyAkeCQgZm9sbG93aW5nIHRoZSByZWxhdGlvbgokJHhfayA9IFxhbHBoYSArIFxiZXRhXCwgXHRhbntcdGhldGFfa30uJCQKClRoZSBwcmlvciBjb25zaWRlcmVkIGlzIGNvbnN0YW50IGluIHRoZSByZWN0YW5nbGUgJChcYWxwaGEsXGJldGEpIFxpbiBcbGVmdFsgLTJcLCBcdGV4dHtrbX0sIDJcLCBcdGV4dHtrbX0gXHJpZ2h0XSBcdGltZXMgXGxlZnRbIDBcLCBcdGV4dHtrbX0sIDVcLCBcdGV4dHtrbX0gXHJpZ2h0XSQgYW5kIG51bGwgZWxzZXdoZXJlLiBUaGUgcG9zdGVyaW9yIG9mIHRoZSBwcm9ibGVtIGlzIHRodXMgZXF1aXZhbGVudCB0byB0aGUgbGlrZWxpaG9vZCBpbiB0aGlzIHJhbmdlIGFuZCBudWxsIGVsc2V3aGVyZS4gVGhlIGxvZy1saWtlbGlob29kIHVzZWQgZm9yIHRoaXMgcHJvYmxlbSBpcyAKJCRcbG9ne1xtYXRoY2Fse0x9KERcLCB8XCwgXGFscGhhLFxiZXRhLE0pfSA9IFxzdW1faSBcbG9nIFxsZWZ0WyBcZGZyYWN7XGJldGF9e1xiZXRhXjIgKyAoeF9pIC0gXGFscGhhKV4yfSBccmlnaHRdJCQgCndoZXJlICREPVx7eF9pXH0kIGlzIHRoZSBzZXQgb2YgeC12YWx1ZXMgbWVhc3VyZWQuCgpgYGB7cn0KIyBmaXggdHJ1ZSBhbHBoYSBhbmQgYmV0YQphbHBoYV90cnVlIDwtIDEgI2ttCmJldGFfdHJ1ZSA8LSAxICNrbQphbHBoYV9taW4gPC0gLTIgI2ttCmFscGhhX21heCA8LSAyICNrbQpiZXRhX21heCA8LSA1ICNrbQoKIyBkZWZpbmUgZ3JpZAphbHBoYTAgPC0gc2VxKGFscGhhX21pbiwgYWxwaGFfbWF4LCBsZW5ndGgub3V0PTEwMDEpCmRfYWxwaGEgPC0gKGFscGhhX21heCAtIGFscGhhX21pbikgLyAxMDAwCmJldGEwIDwtIHNlcSgwLCBiZXRhX21heCwgbGVuZ3RoLm91dD0xMDAxKQpkX2JldGEgPC0gKGJldGFfbWF4IC0gMCkgLyAxMDAwCmdyaWQwIDwtIGV4cGFuZF9ncmlkKGFscGhhPWFscGhhMCwgYmV0YT1iZXRhMCkKCiMgZHJhdyBzYW1wbGVzCm5fbWF4IDwtIDEwMDAKbGlnaHRob3VzZV9zYW1wbGVzIDwtIGFscGhhX3RydWUgKyBiZXRhX3RydWUgKiB0YW4ocnVuaWYobl9tYXgsIG1pbj0tcGkvMiwgbWF4PXBpLzIpKQpgYGAKCgpgYGB7cn0KIyBmdW5jdGlvbiB0aGF0IGNvbXB1dGVzIHBvc3RlcmlvcnMgZm9yIHRoZSBsaWdodGhvdXNlIHByb2JsZW0KY29tcHV0ZV9wb3N0ZXJpb3JfbGlnaHRob3VzZSA8LSBmdW5jdGlvbihncmlkXywgZGFfLCBkYl8sIHNhbXBsZXNfLCBtYXJnaW5hbGl6ZT0iIikgewoKICAjIGxvZy1wb3N0ZXJpb3IKICBwb3N0X2RmIDwtIGdyaWRfICU+JSBtdXRhdGUobG9nX3Bvc3QgPSAwKQogIGZvciAoeF8gaW4gc2FtcGxlc18pIHsKICAgIHBvc3RfZGYgPC0gcG9zdF9kZiAlPiUKICAgICAgICAgICAgICAgbXV0YXRlKGxvZ19wb3N0ID0gbG9nX3Bvc3QgKyBsb2coYmV0YS8oYmV0YSoqMiArICh4XyAtIGFscGhhKSoqMikpKQogIH0KICBwb3N0X2RmIDwtIHBvc3RfZGYgJT4lIG11dGF0ZShsb2dfcG9zdCA9IGxvZ19wb3N0IC0gbWF4KGxvZ19wb3N0KSkKCiAgIyB1bm5vcm1hbGl6ZWQgcG9zdGVyaW9yCiAgcG9zdF9kZiRwb3N0IDwtIGV4cChwb3N0X2RmJGxvZ19wb3N0KQoKCiAgaWYobWFyZ2luYWxpemU9PSJhbHBoYSIpIHsKCiAgICAjIG1hcmdpbmFsaXplIG92ZXIgYmV0YSBhbmQgbm9ybWFsaXplIHRoZSBtYXJnaW5hbGl6ZWQgcG9zdGVyaW9yCiAgICBwb3N0X2FscGhhIDwtIHBvc3RfZGYgJT4lIGdyb3VwX2J5KGFscGhhKSAlPiUgc3VtbWFyaXNlKHBvc3QgPSBzdW0ocG9zdCwgbmEucm0gPSBUUlVFKSkKICAgIHBvc3RfYWxwaGEkcG9zdCA8LSBwb3N0X2FscGhhJHBvc3QgLyAoc3VtKHBvc3RfYWxwaGEkcG9zdCkgKiBkYV8pCgogICAgcmV0dXJuKHBvc3RfYWxwaGEpCiAgfQogIGVsc2UgaWYgKG1hcmdpbmFsaXplPT0iYmV0YSIpIHsKCiAgICAjIG1hcmdpbmFsaXplIG92ZXIgYWxwaGEgYW5kIG5vcm1hbGl6ZSB0aGUgbWFyZ2luYWxpemVkIHBvc3RlcmlvcgogICAgcG9zdF9iZXRhIDwtIHBvc3RfZGYgJT4lIGdyb3VwX2J5KGJldGEpICU+JSBzdW1tYXJpc2UocG9zdCA9IHN1bShwb3N0LCBuYS5ybSA9IFRSVUUpKQogICAgcG9zdF9iZXRhJHBvc3QgPC0gcG9zdF9iZXRhJHBvc3QgLyAoc3VtKHBvc3RfYmV0YSRwb3N0KSAqIGRiXykKCiAgICByZXR1cm4ocG9zdF9iZXRhKQogIH0KICBlbHNlIHsKCiAgICAjIG5vIG1hcmdpbmFsaXphdGlvbgogICAgcmV0dXJuKHBvc3RfZGYpCiAgfQoKfQpgYGAKCgoKYGBge3IsIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTZ9CnBsdF9iYXNlIDwtIGdncGxvdCgpICsKICAgICAgICAgICAgZ2VvbV92bGluZShtYXBwaW5nPWFlcyh4aW50ZXJjZXB0ID0gYWxwaGFfdHJ1ZSksIGNvbG91cj0iZmlyZWJyaWNrIiwgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MSkgKwogICAgICAgICAgICBzY2FsZV94X2NvbnRpbnVvdXMobmFtZT0iQWxwaGEiKSArCiAgICAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhuYW1lPWV4cHJlc3Npb24ocGFzdGUoIlAoICIsIGFscGhhLCAiIHwgRCxNICkiKSkpICsKICAgICAgICAgICAgdGhlbWVfYncoKSArCiAgICAgICAgICAgIHRoZW1lKHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KGhqdXN0PTAuNSkpCgoKIyBwbG90IGFscGhhIHBvc3RlcmlvcgpncmlkLmFycmFuZ2UoCiAgcGx0X2Jhc2UgKyBnZW9tX2xpbmUoZGF0YT1jb21wdXRlX3Bvc3Rlcmlvcl9saWdodGhvdXNlKGdyaWQwLCBkX2FscGhhLCBkX2JldGEsIGxpZ2h0aG91c2Vfc2FtcGxlc1sxXSwgbWFyZ2luYWxpemUgPSAiYWxwaGEiKSwKICAgICAgICAgICAgICAgICAgICAgICBhZXMoeD1hbHBoYSwgeT1wb3N0KSkgKwogICAgICAgICAgICAgbGFicyh0aXRsZT0iTWFyZ2luYWxpemVkIHBvc3RlcmlvciB3aXRoIDEgc2FtcGxlIiksCiAgcGx0X2Jhc2UgKyBnZW9tX2xpbmUoZGF0YT1jb21wdXRlX3Bvc3Rlcmlvcl9saWdodGhvdXNlKGdyaWQwLCBkX2FscGhhLCBkX2JldGEsIGxpZ2h0aG91c2Vfc2FtcGxlc1sxOjJdLCBtYXJnaW5hbGl6ZSA9ICJhbHBoYSIpLAogICAgICAgICAgICAgICAgICAgICAgIGFlcyh4PWFscGhhLCB5PXBvc3QpKSArCiAgICAgICAgICAgICBsYWJzKHRpdGxlPSJNYXJnaW5hbGl6ZWQgcG9zdGVyaW9yIHdpdGggMiBzYW1wbGVzIiksCiAgcGx0X2Jhc2UgKyBnZW9tX2xpbmUoZGF0YT1jb21wdXRlX3Bvc3Rlcmlvcl9saWdodGhvdXNlKGdyaWQwLCBkX2FscGhhLCBkX2JldGEsIGxpZ2h0aG91c2Vfc2FtcGxlc1sxOjVdLCBtYXJnaW5hbGl6ZSA9ICJhbHBoYSIpLAogICAgICAgICAgICAgICAgICAgICAgIGFlcyh4PWFscGhhLCB5PXBvc3QpKSArCiAgICAgICAgICAgICBsYWJzKHRpdGxlPSJNYXJnaW5hbGl6ZWQgcG9zdGVyaW9yIHdpdGggNSBzYW1wbGVzIiksCiAgcGx0X2Jhc2UgKyBnZW9tX2xpbmUoZGF0YT1jb21wdXRlX3Bvc3Rlcmlvcl9saWdodGhvdXNlKGdyaWQwLCBkX2FscGhhLCBkX2JldGEsIGxpZ2h0aG91c2Vfc2FtcGxlc1sxOjEwXSwgbWFyZ2luYWxpemUgPSAiYWxwaGEiKSwKICAgICAgICAgICAgICAgICAgICAgICBhZXMoeD1hbHBoYSwgeT1wb3N0KSkgKwogICAgICAgICAgICAgbGFicyh0aXRsZT0iTWFyZ2luYWxpemVkIHBvc3RlcmlvciB3aXRoIDEwIHNhbXBsZXMiKSwKICBwbHRfYmFzZSArIGdlb21fbGluZShkYXRhPWNvbXB1dGVfcG9zdGVyaW9yX2xpZ2h0aG91c2UoZ3JpZDAsIGRfYWxwaGEsIGRfYmV0YSwgbGlnaHRob3VzZV9zYW1wbGVzWzE6MjBdLCBtYXJnaW5hbGl6ZSA9ICJhbHBoYSIpLAogICAgICAgICAgICAgICAgICAgICAgIGFlcyh4PWFscGhhLCB5PXBvc3QpKSArCiAgICAgICAgICAgICBsYWJzKHRpdGxlPSJNYXJnaW5hbGl6ZWQgcG9zdGVyaW9yIHdpdGggMjAgc2FtcGxlcyIpLAogIHBsdF9iYXNlICsgZ2VvbV9saW5lKGRhdGE9Y29tcHV0ZV9wb3N0ZXJpb3JfbGlnaHRob3VzZShncmlkMCwgZF9hbHBoYSwgZF9iZXRhLCBsaWdodGhvdXNlX3NhbXBsZXNbMTo1MF0sIG1hcmdpbmFsaXplID0gImFscGhhIiksCiAgICAgICAgICAgICAgICAgICAgICAgYWVzKHg9YWxwaGEsIHk9cG9zdCkpICsKICAgICAgICAgICAgIGxhYnModGl0bGU9Ik1hcmdpbmFsaXplZCBwb3N0ZXJpb3Igd2l0aCA1MCBzYW1wbGVzIiksCiAgcGx0X2Jhc2UgKyBnZW9tX2xpbmUoZGF0YT1jb21wdXRlX3Bvc3Rlcmlvcl9saWdodGhvdXNlKGdyaWQwLCBkX2FscGhhLCBkX2JldGEsIGxpZ2h0aG91c2Vfc2FtcGxlc1sxOjEwMF0sIG1hcmdpbmFsaXplID0gImFscGhhIiksCiAgICAgICAgICAgICAgICAgICAgICAgYWVzKHg9YWxwaGEsIHk9cG9zdCkpICsKICAgICAgICAgICAgIGxhYnModGl0bGU9Ik1hcmdpbmFsaXplZCBwb3N0ZXJpb3Igd2l0aCAxMDAgc2FtcGxlcyIpLAogIG5yb3c9NCkKCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTZ9CnBsdF9iYXNlIDwtIGdncGxvdCgpICsKICAgICAgICAgICAgZ2VvbV92bGluZShtYXBwaW5nPWFlcyh4aW50ZXJjZXB0ID0gYmV0YV90cnVlKSwgY29sb3VyPSJmaXJlYnJpY2siLCBsaW5ldHlwZT0iZGFzaGVkIiwgc2l6ZT0xKSArCiAgICAgICAgICAgIHNjYWxlX3hfY29udGludW91cyhuYW1lPSJCZXRhIikgKwogICAgICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMobmFtZT1leHByZXNzaW9uKHBhc3RlKCJQKCAiLCBiZXRhLCAiIHwgRCxNICkiKSkpICsKICAgICAgICAgICAgdGhlbWVfYncoKSArCiAgICAgICAgICAgIHRoZW1lKHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KGhqdXN0PTAuNSkpCgoKIyBwbG90IGJldGEgcG9zdGVyaW9yCmdyaWQuYXJyYW5nZSgKICBwbHRfYmFzZSArIGdlb21fbGluZShkYXRhPWNvbXB1dGVfcG9zdGVyaW9yX2xpZ2h0aG91c2UoZ3JpZDAsIGRfYWxwaGEsIGRfYmV0YSwgbGlnaHRob3VzZV9zYW1wbGVzWzFdLCBtYXJnaW5hbGl6ZSA9ICJiZXRhIiksCiAgICAgICAgICAgICAgICAgICAgICAgYWVzKHg9YmV0YSwgeT1wb3N0KSkgKwogICAgICAgICAgICAgbGFicyh0aXRsZT0iTWFyZ2luYWxpemVkIHBvc3RlcmlvciB3aXRoIDEgc2FtcGxlIiksCiAgcGx0X2Jhc2UgKyBnZW9tX2xpbmUoZGF0YT1jb21wdXRlX3Bvc3Rlcmlvcl9saWdodGhvdXNlKGdyaWQwLCBkX2FscGhhLCBkX2JldGEsIGxpZ2h0aG91c2Vfc2FtcGxlc1sxOjJdLCBtYXJnaW5hbGl6ZSA9ICJiZXRhIiksCiAgICAgICAgICAgICAgICAgICAgICAgYWVzKHg9YmV0YSwgeT1wb3N0KSkgKwogICAgICAgICAgICAgbGFicyh0aXRsZT0iTWFyZ2luYWxpemVkIHBvc3RlcmlvciB3aXRoIDIgc2FtcGxlcyIpLAogIHBsdF9iYXNlICsgZ2VvbV9saW5lKGRhdGE9Y29tcHV0ZV9wb3N0ZXJpb3JfbGlnaHRob3VzZShncmlkMCwgZF9hbHBoYSwgZF9iZXRhLCBsaWdodGhvdXNlX3NhbXBsZXNbMTo1XSwgbWFyZ2luYWxpemUgPSAiYmV0YSIpLAogICAgICAgICAgICAgICAgICAgICAgIGFlcyh4PWJldGEsIHk9cG9zdCkpICsKICAgICAgICAgICAgIGxhYnModGl0bGU9Ik1hcmdpbmFsaXplZCBwb3N0ZXJpb3Igd2l0aCA1IHNhbXBsZXMiKSwKICBwbHRfYmFzZSArIGdlb21fbGluZShkYXRhPWNvbXB1dGVfcG9zdGVyaW9yX2xpZ2h0aG91c2UoZ3JpZDAsIGRfYWxwaGEsIGRfYmV0YSwgbGlnaHRob3VzZV9zYW1wbGVzWzE6MTBdLCBtYXJnaW5hbGl6ZSA9ICJiZXRhIiksCiAgICAgICAgICAgICAgICAgICAgICAgYWVzKHg9YmV0YSwgeT1wb3N0KSkgKwogICAgICAgICAgICAgbGFicyh0aXRsZT0iTWFyZ2luYWxpemVkIHBvc3RlcmlvciB3aXRoIDEwIHNhbXBsZXMiKSwKICBwbHRfYmFzZSArIGdlb21fbGluZShkYXRhPWNvbXB1dGVfcG9zdGVyaW9yX2xpZ2h0aG91c2UoZ3JpZDAsIGRfYWxwaGEsIGRfYmV0YSwgbGlnaHRob3VzZV9zYW1wbGVzWzE6MjBdLCBtYXJnaW5hbGl6ZSA9ICJiZXRhIiksCiAgICAgICAgICAgICAgICAgICAgICAgYWVzKHg9YmV0YSwgeT1wb3N0KSkgKwogICAgICAgICAgICAgbGFicyh0aXRsZT0iTWFyZ2luYWxpemVkIHBvc3RlcmlvciB3aXRoIDIwIHNhbXBsZXMiKSwKICBwbHRfYmFzZSArIGdlb21fbGluZShkYXRhPWNvbXB1dGVfcG9zdGVyaW9yX2xpZ2h0aG91c2UoZ3JpZDAsIGRfYWxwaGEsIGRfYmV0YSwgbGlnaHRob3VzZV9zYW1wbGVzWzE6NTBdLCBtYXJnaW5hbGl6ZSA9ICJiZXRhIiksCiAgICAgICAgICAgICAgICAgICAgICAgYWVzKHg9YmV0YSwgeT1wb3N0KSkgKwogICAgICAgICAgICAgbGFicyh0aXRsZT0iTWFyZ2luYWxpemVkIHBvc3RlcmlvciB3aXRoIDUwIHNhbXBsZXMiKSwKICBwbHRfYmFzZSArIGdlb21fbGluZShkYXRhPWNvbXB1dGVfcG9zdGVyaW9yX2xpZ2h0aG91c2UoZ3JpZDAsIGRfYWxwaGEsIGRfYmV0YSwgbGlnaHRob3VzZV9zYW1wbGVzWzE6MTAwXSwgbWFyZ2luYWxpemUgPSAiYmV0YSIpLAogICAgICAgICAgICAgICAgICAgICAgIGFlcyh4PWJldGEsIHk9cG9zdCkpICsKICAgICAgICAgICAgIGxhYnModGl0bGU9Ik1hcmdpbmFsaXplZCBwb3N0ZXJpb3Igd2l0aCAxMDAgc2FtcGxlcyIpLAogIG5yb3c9NCkKYGBgCgoKCgpgYGB7ciwgZmlnLmhlaWdodD03LCBmaWcud2lkdGg9NX0KcGx0X2Jhc2UgPC0gZ2dwbG90KCkgKwogICAgICAgICAgICBzY2FsZV94X2NvbnRpbnVvdXMobmFtZT0iQWxwaGEiKSArCiAgICAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhuYW1lPSJCZXRhIikgKwogICAgICAgICAgICB0aGVtZShwbG90LnRpdGxlPWVsZW1lbnRfdGV4dChoanVzdD0wLjUpKSArCiAgICAgICAgICAgIHRoZW1lX2J3KCkKCmdyaWQuYXJyYW5nZSgKICBwbHRfYmFzZSArIGdlb21fY29udG91cl9maWxsZWQoZGF0YT1jb21wdXRlX3Bvc3Rlcmlvcl9saWdodGhvdXNlKGdyaWQwLCBkX2FscGhhLCBkX2JldGEsIGxpZ2h0aG91c2Vfc2FtcGxlc1sxOjJdKSwKICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9YWxwaGEsIHk9YmV0YSwgej1wb3N0KSwgc2hvdy5sZWdlbmQ9RkFMU0UpICsKICAgICAgICAgICAgIGdlb21fdmxpbmUobWFwcGluZz1hZXMoeGludGVyY2VwdCA9IGFscGhhX3RydWUpLCBjb2xvdXI9ImZpcmVicmljayIsIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTEpICsKICAgICAgICAgICAgIGdlb21faGxpbmUobWFwcGluZz1hZXMoeWludGVyY2VwdCA9IGJldGFfdHJ1ZSksIGNvbG91cj0iZmlyZWJyaWNrIiwgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MSkgKwogICAgICAgICAgICAgbGFicyh0aXRsZT0iUG9zdGVyaW9yIHdpdGggMiBzYW1wbGVzIikgKwogICAgICAgICAgICAgdGhlbWUocGxvdC50aXRsZT1lbGVtZW50X3RleHQoaGp1c3Q9MC41KSksCiAgcGx0X2Jhc2UgKyBnZW9tX2NvbnRvdXJfZmlsbGVkKGRhdGE9Y29tcHV0ZV9wb3N0ZXJpb3JfbGlnaHRob3VzZShncmlkMCwgZF9hbHBoYSwgZF9iZXRhLCBsaWdodGhvdXNlX3NhbXBsZXNbMTo1XSksCiAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PWFscGhhLCB5PWJldGEsIHo9cG9zdCksIHNob3cubGVnZW5kPUZBTFNFKSArCiAgICAgICAgICAgICBnZW9tX3ZsaW5lKG1hcHBpbmc9YWVzKHhpbnRlcmNlcHQgPSBhbHBoYV90cnVlKSwgY29sb3VyPSJmaXJlYnJpY2siLCBsaW5ldHlwZT0iZGFzaGVkIiwgc2l6ZT0xKSArCiAgICAgICAgICAgICBnZW9tX2hsaW5lKG1hcHBpbmc9YWVzKHlpbnRlcmNlcHQgPSBiZXRhX3RydWUpLCBjb2xvdXI9ImZpcmVicmljayIsIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTEpICsKICAgICAgICAgICAgIGxhYnModGl0bGU9IlBvc3RlcmlvciB3aXRoIDUgc2FtcGxlcyIpICsKICAgICAgICAgICAgIHRoZW1lKHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KGhqdXN0PTAuNSkpLAogIHBsdF9iYXNlICsgZ2VvbV9jb250b3VyX2ZpbGxlZChkYXRhPWNvbXB1dGVfcG9zdGVyaW9yX2xpZ2h0aG91c2UoZ3JpZDAsIGRfYWxwaGEsIGRfYmV0YSwgbGlnaHRob3VzZV9zYW1wbGVzWzE6MTBdKSwKICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9YWxwaGEsIHk9YmV0YSwgej1wb3N0KSwgc2hvdy5sZWdlbmQ9RkFMU0UpICsKICAgICAgICAgICAgIGdlb21fdmxpbmUobWFwcGluZz1hZXMoeGludGVyY2VwdCA9IGFscGhhX3RydWUpLCBjb2xvdXI9ImZpcmVicmljayIsIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTEpICsKICAgICAgICAgICAgIGdlb21faGxpbmUobWFwcGluZz1hZXMoeWludGVyY2VwdCA9IGJldGFfdHJ1ZSksIGNvbG91cj0iZmlyZWJyaWNrIiwgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MSkgKwogICAgICAgICAgICAgbGFicyh0aXRsZT0iUG9zdGVyaW9yIHdpdGggMTAgc2FtcGxlcyIpICsKICAgICAgICAgICAgIHRoZW1lKHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KGhqdXN0PTAuNSkpLAogIHBsdF9iYXNlICsgZ2VvbV9jb250b3VyX2ZpbGxlZChkYXRhPWNvbXB1dGVfcG9zdGVyaW9yX2xpZ2h0aG91c2UoZ3JpZDAsIGRfYWxwaGEsIGRfYmV0YSwgbGlnaHRob3VzZV9zYW1wbGVzWzE6MjBdKSwKICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9YWxwaGEsIHk9YmV0YSwgej1wb3N0KSwgc2hvdy5sZWdlbmQ9RkFMU0UpICsKICAgICAgICAgICAgIGdlb21fdmxpbmUobWFwcGluZz1hZXMoeGludGVyY2VwdCA9IGFscGhhX3RydWUpLCBjb2xvdXI9ImZpcmVicmljayIsIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTEpICsKICAgICAgICAgICAgIGdlb21faGxpbmUobWFwcGluZz1hZXMoeWludGVyY2VwdCA9IGJldGFfdHJ1ZSksIGNvbG91cj0iZmlyZWJyaWNrIiwgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MSkgKwogICAgICAgICAgICAgbGFicyh0aXRsZT0iUG9zdGVyaW9yIHdpdGggMjAgc2FtcGxlcyIpICsKICAgICAgICAgICAgIHRoZW1lKHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KGhqdXN0PTAuNSkpLAogIHBsdF9iYXNlICsgZ2VvbV9jb250b3VyX2ZpbGxlZChkYXRhPWNvbXB1dGVfcG9zdGVyaW9yX2xpZ2h0aG91c2UoZ3JpZDAsIGRfYWxwaGEsIGRfYmV0YSwgbGlnaHRob3VzZV9zYW1wbGVzWzE6NTBdKSwKICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9YWxwaGEsIHk9YmV0YSwgej1wb3N0KSwgc2hvdy5sZWdlbmQ9RkFMU0UpICsKICAgICAgICAgICAgIGdlb21fdmxpbmUobWFwcGluZz1hZXMoeGludGVyY2VwdCA9IGFscGhhX3RydWUpLCBjb2xvdXI9ImZpcmVicmljayIsIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTEpICsKICAgICAgICAgICAgIGdlb21faGxpbmUobWFwcGluZz1hZXMoeWludGVyY2VwdCA9IGJldGFfdHJ1ZSksIGNvbG91cj0iZmlyZWJyaWNrIiwgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MSkgKwogICAgICAgICAgICAgbGFicyh0aXRsZT0iUG9zdGVyaW9yIHdpdGggNTAgc2FtcGxlcyIpICsKICAgICAgICAgICAgIHRoZW1lKHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KGhqdXN0PTAuNSkpLAogIHBsdF9iYXNlICsgZ2VvbV9jb250b3VyX2ZpbGxlZChkYXRhPWNvbXB1dGVfcG9zdGVyaW9yX2xpZ2h0aG91c2UoZ3JpZDAsIGRfYWxwaGEsIGRfYmV0YSwgbGlnaHRob3VzZV9zYW1wbGVzWzE6MTAwXSksCiAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PWFscGhhLCB5PWJldGEsIHo9cG9zdCksIHNob3cubGVnZW5kPUZBTFNFKSArCiAgICAgICAgICAgICBnZW9tX3ZsaW5lKG1hcHBpbmc9YWVzKHhpbnRlcmNlcHQgPSBhbHBoYV90cnVlKSwgY29sb3VyPSJmaXJlYnJpY2siLCBsaW5ldHlwZT0iZGFzaGVkIiwgc2l6ZT0xKSArCiAgICAgICAgICAgICBnZW9tX2hsaW5lKG1hcHBpbmc9YWVzKHlpbnRlcmNlcHQgPSBiZXRhX3RydWUpLCBjb2xvdXI9ImZpcmVicmljayIsIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTEpICsKICAgICAgICAgICAgIGxhYnModGl0bGU9IlBvc3RlcmlvciB3aXRoIDEwMCBzYW1wbGVzIikgKwogICAgICAgICAgICAgdGhlbWUocGxvdC50aXRsZT1lbGVtZW50X3RleHQoaGp1c3Q9MC41KSksCiAgbnJvdz0zKQpgYGAKCmBgYHtyfQojIGZpbmQgbW9zdCBwcm9iYWJsZXMgKGFscGhhLGJldGEpIGZvciBlYWNoIGl0ZXJhdGlvbgptYXhfcHJvYl9hbHBoYSA8LSBjKCkKbWF4X3Byb2JfYmV0YSA8LSBjKCkKam9pbnRfcG9zdF9kZiA8LSBncmlkMCAlPiUgbXV0YXRlKGxvZ19wb3N0ID0gMCkKCmZvcih4XyBpbiBsaWdodGhvdXNlX3NhbXBsZXNbMToxMDBdKSB7CiAgam9pbnRfcG9zdF9kZiA8LSBqb2ludF9wb3N0X2RmICU+JQogICAgICAgICAgICAgICAgICAgbXV0YXRlKGxvZ19wb3N0ID0gbG9nX3Bvc3QgKyBsb2coYmV0YS8oYmV0YSoqMiArICh4XyAtIGFscGhhKSoqMikpKQogIAogIG1heF9pbmR4IDwtIHdoaWNoLm1heChqb2ludF9wb3N0X2RmJGxvZ19wb3N0KQogIG1heF9wcm9iX2FscGhhIDwtIGMobWF4X3Byb2JfYWxwaGEsIGpvaW50X3Bvc3RfZGZbW21heF9pbmR4LCAiYWxwaGEiXV0pCiAgbWF4X3Byb2JfYmV0YSA8LSBjKG1heF9wcm9iX2JldGEsIGpvaW50X3Bvc3RfZGZbW21heF9pbmR4LCAiYmV0YSJdXSkKfQoKIyBwbG90IHN1Y2Nlc3Npb24gb2YgbW9zdCBwcm9iYWJsZSB2YWx1ZXMKcGx0X21heF9wcm9iX2V2b2wgPC0gZ2dwbG90KGRhdGE9ZGF0YS5mcmFtZShBbHBoYT1tYXhfcHJvYl9hbHBoYSwgQmV0YT1tYXhfcHJvYl9iZXRhKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmc9YWVzKHg9QWxwaGEsIHk9QmV0YSkpICsKICAgICAgICAgICAgICAgICAgICAgZ2VvbV9wYXRoKCkgKwogICAgICAgICAgICAgICAgICAgICBnZW9tX3ZsaW5lKG1hcHBpbmc9YWVzKHhpbnRlcmNlcHQgPSBhbHBoYV90cnVlKSwgY29sb3VyPSJmaXJlYnJpY2siLCBsaW5ldHlwZT0iZGFzaGVkIiwgc2l6ZT0xKSArCiAgICAgICAgICAgICAgICAgICAgIGdlb21faGxpbmUobWFwcGluZz1hZXMoeWludGVyY2VwdCA9IGJldGFfdHJ1ZSksIGNvbG91cj0iZmlyZWJyaWNrIiwgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MSkgKwogICAgICAgICAgICAgICAgICAgICBnZW9tX3BvaW50KCkgKwogICAgICAgICAgICAgICAgICAgICBnZW9tX3BvaW50KGFlcyh4PWFscGhhX3RydWUsIHk9YmV0YV90cnVlKSwgY29sb3VyPSJmaXJlYnJpY2siKSArCiAgICAgICAgICAgICAgICAgICAgIGdlb21fdGV4dChkYXRhPWRhdGEuZnJhbWUoYWxwaGE9bWF4X3Byb2JfYWxwaGFbMToxMF0sIGJldGE9bWF4X3Byb2JfYmV0YVsxOjEwXSwgbGFiZWxzPTE6MTApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZz1hZXMoeD1hbHBoYSswLjA1LCB5PWJldGErMC4wNSwgbGFiZWwgPSBsYWJlbHMpKSArCiAgICAgICAgICAgICAgICAgICAgIGxhYnModGl0bGU9ZXhwcmVzc2lvbihwYXN0ZSgiRXZvbHV0aW9uIG9mIHRoZSBtb3N0IHByb2JhYmxlcyAoIiwgYWxwaGEsICIgLCAiLCBiZXRhLCAiKSBhcyBhIGZ1bmN0aW9uIG9mIG51bWJlciBvZiBkYXRhIHNhbXBsZXMiKSkpICsKICAgICAgICAgICAgICAgICAgICAgdGhlbWVfYncoKSArCiAgICAgICAgICAgICAgICAgICAgIHRoZW1lKHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KGhqdXN0PTAuNSkpCiAgICAgICAgICAgICAgICAgICAgIAoKcGx0X21heF9wcm9iX2V2b2wKYGBgCgoqKkFzIGV4cGVjdGVkLCBieSB1cGRhdGluZyBpdGVyYXRpdmVseSB0aGUgcG9zdGVyaW9yIHdpdGggdGhlIGRhdGEsIHRoZSBwb3N0ZXJpb3IgZGlzdHJpYnV0aW9uIGJlY29tZXMgbW9yZSBhbmQgbW9yZSBwZWFrZWQgYXJvdW5kIHRoZSB0cnVlIHZhbHVlIG9mIHRoZSBwYXJhbWV0ZXJzICRcYWxwaGEsIFxiZXRhJC4qKgoKCgojIyBFeGVyY2lzZSAzCgpHaXZlbiB0aGUgU2lnbmFsIG92ZXIgQmFja2dyb3VuZCBleGFtcGxlIGRpc2N1c3NlZCBsYXN0IHdlZWssIGFuYWx5emUgYW5kIGRpc2N1c3MgdGhlIGZvbGxvd2luZyBjYXNlcy4KClRoZSBzaWduYWwgaXMgbW9kZWxlZCBieSB0aGUgZm9sbG93aW5nIGZ1bmN0aW9uOgoKJCQgU1wsKHhcLHxcLEEsQix4XzAsdyxcRGVsdGEgdCkgPSBcRGVsdGEgdCBcbGVmdCggQVwsIGVeey1cZGZyYWN7MX17Mn0gXGxlZnQoXGRmcmFje3gteF8wfXt3fVxyaWdodCleMiB9ICtCIFxyaWdodCkuJCQKClRoZSBwcmlvciBjb25zaWRlcmVkIGlzIGNvbnN0YW50IGluIHRoZSByZWN0YW5nbGUgJChBLEIpIFxpbiBcbGVmdFsgMCwgNSBccmlnaHRdIFx0aW1lcyBcbGVmdFsgMC41LCAxLjUgXHJpZ2h0XSQgYW5kIG51bGwgZWxzZXdoZXJlLiBUaGUgcG9zdGVyaW9yIG9mIHRoZSBwcm9ibGVtIGlzIHRodXMgZXF1aXZhbGVudCB0byB0aGUgbGlrZWxpaG9vZCBpbiB0aGlzIHJhbmdlIGFuZCBudWxsIGVsc2V3aGVyZS4gVGhlIGxvZy1saWtlbGlob29kIHVzZWQgZm9yIHRoaXMgcHJvYmxlbSBpcyAKJCRcbG9ne1xtYXRoY2Fse0x9KERcLCB8XCwgQSxCLE0pfSA9IFxzdW1faSBcbGVmdFsgTl9pIFxsbntTXCwoeF9pXCx8XCxBLEIpfSAtIFNcLCh4X2lcLHxcLEEsQikgLSBcbG57KE5faSEpfSBccmlnaHRdJCQKd2hlcmUgJEQ9XHtOX2lcfSQgaXMgdGhlIHNldCBvZiBjb3VudHMgbWVhc3VyZWQgaW4gdGhlIHBvc2l0aW9ucyAkXHt4X2lcfSQuCmBgYHtyfQojIChzdGFydGluZykgbW9kZWwgZGVmaW5pdGlvbnMKeDAgPC0gMAp3IDwtIDEKQV90cnVlIDwtIDIKQl90cnVlIDwtIDEKZHQgPC0gNQp4X2dyaWQgPC0gc2VxKC03KncsIDcqdywgYnk9MC41KncpCgojIGRlZmluZSBncmlkIGZvciBwYXJhbWV0ZXJzIEEsQgpBX21heCA8LSA1CkJfbWluIDwtIDAuNQpCX21heCA8LSAxLjUKQTAgPC0gc2VxKDAsIEFfbWF4LCBsZW5ndGgub3V0PTEwMDEpCmRBIDwtIChBX21heCAtIDApIC8gMTAwMApCMCA8LSBzZXEoQl9taW4sIEJfbWF4LCBsZW5ndGgub3V0PTEwMDEpCmRCIDwtIChCX21heCAtIEJfbWluKSAvIDEwMDAKZ3JpZDAgPC0gZXhwYW5kX2dyaWQoQT1BMCwgQj1CMCkKCgojIHNpZ25hbCBkZWZpbml0aW9uCnNpZ25hbCA8LSBmdW5jdGlvbih4LCBBLCBCLCB4MCwgdywgZHQpIHsKICBkdCAqIChBICogZXhwKC0wLjUqKCh4LXgwKS93KSoqMikgKyBCKQp9CgojIHRydWUgc2lnbmFsCnNpZ25hbF90cnVlX2RmIDwtIHRpYmJsZSh4PXhfZ3JpZCwgU2lnbmFsPXNpZ25hbCh4X2dyaWQsIEFfdHJ1ZSwgQl90cnVlLCB4MCwgdywgZHQpKQpwbHRfU0IgPC0gZ2dwbG90KCkgKwogICAgICAgICAgZ2VvbV9saW5lKGRhdGE9c2lnbmFsX3RydWVfZGYsIG1hcHBpbmc9YWVzKHg9eCwgeT1TaWduYWwpKSArCiAgICAgICAgICBsYWJzKHRpdGxlPSJSZWFsIHNpZ25hbCB2cyBtZWFzdXJlZCBzaWduYWwgd2l0aCBBL0I9MiBhbmQgdz0xIikgKwogICAgICAgICAgc2NhbGVfeV9jb250aW51b3VzKG5hbWUgPSBleHByZXNzaW9uKHBhc3RlKCJTaWduYWwgKHggfCBBLCBCLCAiLCB4WzBdLCAiLCB3LCAiLCBEZWx0YSwgInQsIE0pIikpKSArCiAgICAgICAgICB0aGVtZV9idygpICsKICAgICAgICAgIHRoZW1lKHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KGhqdXN0PTAuNSkpCiAgICAgICAgICAKCiMgc2FtcGxlIHNpZ25hbHMKc2lnbmFsX3NhbXBsZXMgPC0gcnBvaXMobGVuZ3RoKHhfZ3JpZCksIHNpZ25hbF90cnVlX2RmJFNpZ25hbCkKc2lnbmFsX3NhbXBsZXNfZGYgPC0gdGliYmxlKHg9eF9ncmlkLCBOPXNpZ25hbF9zYW1wbGVzKQpwbHRfU0IgPC0gcGx0X1NCICsKICAgICAgICAgIGdlb21fY29sKGRhdGE9c2lnbmFsX3NhbXBsZXNfZGYsIG1hcHBpbmc9YWVzKHg9eCwgeT1OKSwgYWxwaGE9MC4zKQoKcGx0X1NCCmBgYAoKCgpgYGB7cn0KIyBmdW5jdGlvbiB0aGF0IGNvbXB1dGVzIHRoZSBwb3N0ZXJpb3IgZm9yIHRoZSBTaWduYWwvQmFja2dyb3VuZCBwcm9ibGVtLAojIGl0IGNvbXB1dGVzIHRoZSBwb3N0ZXJpb3IgZm9yIGRpZmZlcmVudCB2YWx1ZXMgb2YgdGhlIHBhcmFtZXRlcnMKIyB3LCBBX3RydWUsIEJfdHJ1ZSwgeDAsIGR0CmNvbXB1dGVfcG9zdGVyaW9yX1NCIDwtIGZ1bmN0aW9uKHgwPTAsIHc9MSwgQV90cnVlPTIsIEJfdHJ1ZT0xLCBkdD01LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBBX21heD01LCBCX21pbj0wLjUsIEJfbWF4PTEuNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFyZ2luYWxpemU9IiIpIHsKICAKICAjIHJlcHJvZHVjaWJpbGl0eQogIHNldC5zZWVkKDEyMzQ1KQogIAogICMgZGVmaW5lIGdyaWQKICBncmlkX3hfIDwtIHNlcSgtNyp3LCA3KncsIGJ5PTAuNSp3KQogIGdyaWRfIDwtIGV4cGFuZF9ncmlkKEE9c2VxKDAsIEFfbWF4LCBsZW5ndGgub3V0PTEwMDEpLCBCPXNlcShCX21pbiwgQl9tYXgsIGxlbmd0aC5vdXQ9MTAwMSkpCiAgZEFfIDwtIChBX21heCAtIDApIC8gMTAwMAogIGRCXyA8LSAoQl9tYXggLSBCX21pbikgLyAxMDAwCiAgCiAgCiAgIyB0cnVlIHNpZ25hbAogIHNpZ25hbF90cnVlIDwtIHNpZ25hbChncmlkX3hfLCBBX3RydWUsIEJfdHJ1ZSwgeDAsIHcsIGR0KQogIAogICMgc2FtcGxlIHNpZ25hbHMKICBzYW1wbGVzXyA8LSBycG9pcyhuPWxlbmd0aChncmlkX3hfKSwgbGFtYmRhPXNpZ25hbF90cnVlKQogIAogIAogIAogICMgbG9nLXBvc3RlcmlvcgogIHBvc3RfZGYgPC0gZ3JpZF8gJT4lIG11dGF0ZShsb2dfcG9zdCA9IDApCiAgZm9yIChpIGluIDE6bGVuZ3RoKHNhbXBsZXNfKSkgewogICAgcG9zdF9kZiA8LSBwb3N0X2RmICU+JQogICAgICAgICAgICAgICBtdXRhdGUobG9nX3Bvc3QgPSBsb2dfcG9zdCArIGRwb2lzKHg9c2FtcGxlc19baV0sIGxhbWJkYSA9IHNpZ25hbChncmlkX3hfW2ldLCBBLCBCLCB4MD14MCwgdz13LCBkdD1kdCksIGxvZz1UUlVFKSkKICB9CiAgcG9zdF9kZiA8LSBwb3N0X2RmICU+JSBtdXRhdGUobG9nX3Bvc3QgPSBsb2dfcG9zdCAtIG1heChsb2dfcG9zdCkpCgogICMgdW5ub3JtYWxpemVkIHBvc3RlcmlvcgogIHBvc3RfZGYkUG9zdGVyaW9yIDwtIGV4cChwb3N0X2RmJGxvZ19wb3N0KQogIAogIAogIAogIGlmKG1hcmdpbmFsaXplPT0iQSIpIHsKCiAgICAjIG1hcmdpbmFsaXplIG92ZXIgQiBhbmQgbm9ybWFsaXplIHRoZSBtYXJnaW5hbGl6ZWQgcG9zdGVyaW9yCiAgICBwb3N0X0EgPC0gcG9zdF9kZiAlPiUgZ3JvdXBfYnkoQSkgJT4lIHN1bW1hcmlzZShQb3N0ZXJpb3IgPSBzdW0oUG9zdGVyaW9yLCBuYS5ybSA9IFRSVUUpKQogICAgcG9zdF9BJFBvc3RlcmlvciA8LSBwb3N0X0EkUG9zdGVyaW9yIC8gKHN1bShwb3N0X0EkUG9zdGVyaW9yKSAqIGRBXykKCiAgICByZXR1cm4ocG9zdF9BKQogIH0KICBlbHNlIGlmIChtYXJnaW5hbGl6ZT09IkIiKSB7CgogICAgIyBtYXJnaW5hbGl6ZSBvdmVyIEEgYW5kIG5vcm1hbGl6ZSB0aGUgbWFyZ2luYWxpemVkIHBvc3RlcmlvcgogICAgcG9zdF9CIDwtIHBvc3RfZGYgJT4lIGdyb3VwX2J5KEIpICU+JSBzdW1tYXJpc2UoUG9zdGVyaW9yID0gc3VtKFBvc3RlcmlvciwgbmEucm0gPSBUUlVFKSkKICAgIHBvc3RfQiRQb3N0ZXJpb3IgPC0gcG9zdF9CJFBvc3RlcmlvciAvIChzdW0ocG9zdF9CJFBvc3RlcmlvcikgKiBkQl8pCgogICAgcmV0dXJuKHBvc3RfQikKICB9CiAgZWxzZSB7CgogICAgIyBubyBtYXJnaW5hbGl6YXRpb24KICAgIHJldHVybihwb3N0X2RmKQogIH0KICAKfQpgYGAKCgojIyMgRXhlcmNpc2UgM2EKVmFyeSB0aGUgc2FtcGxpbmcgcmVzb2x1dGlvbiB1c2VkIHRvIGdlbmVyYXRlIHRoZSBkYXRhLCBrZWVwaW5nIHRoZSBzYW1lIHNhbXBsaW5nIHJhbmdlLgpDaGFuZ2UgdGhlIHJlc29sdXRpb24gdyA9IHswLjEsIDAuMjUsIDEsIDIsIDN9IGFuZCBjaGVjayB0aGUgZWZmZWN0IG9uIHRoZSByZXN1bHRzLgoKCmBgYHtyfQpwbG90X3NpZ25hbCA8LSBmdW5jdGlvbih4MD0wLCB3PTEsIEFfdHJ1ZT0yLCBCX3RydWU9MSwgZHQ9NSwKICAgICAgICAgICAgICAgICAgICAgICAgQV9tYXg9NSwgQl9taW49MC41LCBCX21heD0xLjUsIHhsaW09YygtOCp3LDgqdykpIHsKICAKICAjIHJlcHJvZHVjaWJpbGl0eQogICNzZXQuc2VlZCgxMjM0NSkKICAKICAjIGRlZmluZSBncmlkCiAgZ3JpZF94XyA8LSBzZXEoLTcqdywgNyp3LCBieT0wLjUqdykKICAKICAjIHRydWUgc2lnbmFsCiAgc2lnbmFsX3RydWUgPC0gc2lnbmFsKGdyaWRfeF8sIEFfdHJ1ZSwgQl90cnVlLCB4MCwgdywgZHQpCiAgc2lnbmFsX3RydWVfZGYgPC0gdGliYmxlKHg9Z3JpZF94XywgU2lnbmFsPXNpZ25hbF90cnVlKQogIAogICMgc2FtcGxlIHNpZ25hbHMKICBzaWduYWxfc2FtcGxlcyA8LSBycG9pcyhsZW5ndGgoZ3JpZF94XyksIHNpZ25hbF90cnVlX2RmJFNpZ25hbCkKICBzaWduYWxfc2FtcGxlc19kZiA8LSB0aWJibGUoeD1ncmlkX3hfLCBOPXNpZ25hbF9zYW1wbGVzKQogIAogIAogIAogICMgcGxvdAogIHBsdCA8LSBnZ3Bsb3QoKSArCiAgICAgICAgIGdlb21fbGluZShkYXRhPXNpZ25hbF90cnVlX2RmLCBtYXBwaW5nPWFlcyh4PXgsIHk9U2lnbmFsKSkgKwogICAgICAgICBnZW9tX2NvbChkYXRhPXNpZ25hbF9zYW1wbGVzX2RmLCBtYXBwaW5nPWFlcyh4PXgsIHk9TiksIGFscGhhPTAuMykgKwogICAgICAgICBsYWJzKHRpdGxlPXBhc3RlMCgiUmVhbCBzaWduYWwgdnMgbWVhc3VyZWQgc2lnbmFsIHdpdGggQS9CPSIsIEFfdHJ1ZS9CX3RydWUsICIgYW5kIHc9IiwgdywgY29sbGFwc2UgPSAiIikpICsKICAgICAgICAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cz14bGltKSArCiAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhuYW1lID0gZXhwcmVzc2lvbihwYXN0ZSgiU2lnbmFsICh4IHwgQSwgQiwgIiwgeFswXSwgIiwgdywgIiwgRGVsdGEsICJ0LCBNKSIpKSkgKwogICAgICAgICB0aGVtZV9idygpICsKICAgICAgICAgdGhlbWUocGxvdC50aXRsZT1lbGVtZW50X3RleHQoaGp1c3Q9MC41KSkKICAKICByZXR1cm4ocGx0KQp9CmBgYAoKCgoKYGBge3IsIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTZ9CiMgcGxvdCByZWFsIHNpZ25hbHMgdnMgbWVhc3VyZWQgc2lnbmFsIGFzIGEgZnVuY3Rpb24gb2YgdwpncmlkLmFycmFuZ2UoCnBsb3Rfc2lnbmFsKHc9MC4xLCBBX3RydWU9MiwgQl90cnVlPTEsIHhsaW09YygtMjIsMjIpKSwKcGxvdF9zaWduYWwodz0wLjI1LCBBX3RydWU9MiwgQl90cnVlPTEsIHhsaW09YygtMjIsMjIpKSwKcGxvdF9zaWduYWwodz0xLCBBX3RydWU9MiwgQl90cnVlPTEsIHhsaW09YygtMjIsMjIpKSwKcGxvdF9zaWduYWwodz0yLCBBX3RydWU9MiwgQl90cnVlPTEsIHhsaW09YygtMjIsMjIpKSwKcGxvdF9zaWduYWwodz0zLCBBX3RydWU9MiwgQl90cnVlPTEsIHhsaW09YygtMjIsMjIpKSwKbnJvdz0zKQpgYGAKCgoqKkFzIGl0IGlzIHBvc3NpYmxlIHRvIHNlZSBmcm9tIHRoZSBwbG90cyBhYm92ZSwgdGhlIGNoYW5nZSBvZiB0aGUgc2NhbGUgcGFyYW1ldGVyICR3JCBpZiB0aGUgc2FtcGxpbmcgcmFuZ2UgcmVtYWlucyBmaXhlZCBhZmZlY3RzIHRoZSBzcGF0aWFsIHdpZHRoIG9mIHRoZSBzaWduYWwgYnV0IG5vdCB0aGUgcGFyYW1ldGVycyAkQSxCJC4gVGhlIHBsb3RzIGJlbG93IHNob3cgdGhlIGluZGVwZW5kZW5jZSBvZiAkQSxCJCBvbiAkdyQgd2hlbiB0aGUgc2FtcGxpbmcgcmFuZ2UgaXMgZml4ZWQuIFRoaXMgZWZmZWN0IG9jY3VycyBiZWNhdXNlIHRoZSBzaWduYWwgZGVwZW5kcyBvbmx5IG9uIHRoZSByYXRpbyAkeC93JCAoJHhfMD0wJCkgYW5kIG5vdCBzaW5ndWxhcmx5IG9uIHRoZSB0d28gdmFyaWFibGVzLiBTaW5jZSB0aGUgeC1ncmlkIGlzIHByb3BvcnRpb25hbCB0byAkdyQsIHRoZSBzaWduYWwgZ2VuZXJhdGVkIGFyZSBleGFjdGx5IHRoZSBzYW1lLiBUbyBzZWUgc29tZSBjaGFuZ2VzIGluIHRoZSBwbG90cyB3ZSBjb3VsZCBmaXggdGhlIHNwYXRpYWwgKHgtKXdpZHRoIG9mIHRoZSBzaWduYWwgYW5kIHZhcnkgdGhlIHBhcmFtZXRlciAkdyQgaW4gb3JkZXIgdG8gdmFyeSB0aGUgbnVtYmVyIG9mIGNoYW5uZWxzIHRoYXQgY2FuIGNvbGxlY3QgdGhlIHNpZ25hbC4qKgoKCmBgYHtyLCBmaWcud2lkdGg9NX0KIyBwbG90IHR3byBwb3N0ZXJpb3JzIGFzIGFuIGV4YW1wbGUgb2YgaW52YXJpYW5jZSB3LnIudC4gdyBwYXJhbWV0ZXIKZ3JpZC5hcnJhbmdlKAogIGdncGxvdCgpICsgZ2VvbV9jb250b3VyX2ZpbGxlZChkYXRhPWNvbXB1dGVfcG9zdGVyaW9yX1NCKHc9MC4xKSwgbWFwcGluZyA9IGFlcyh4PUEsIHk9Qiwgej1Qb3N0ZXJpb3IpLCBzaG93LmxlZ2VuZD1GQUxTRSkgKwogICAgICAgICAgICAgbGFicyh0aXRsZT1wYXN0ZSgiUG9zdGVyaW9yIHdpdGggQS9CPTIgYW5kIHc9MC4xIikpICsKICAgICAgICAgICAgIHRoZW1lX2J3KCkgKwogICAgICAgICAgICAgdGhlbWUocGxvdC50aXRsZT1lbGVtZW50X3RleHQoaGp1c3Q9MC41KSksCiAgZ2dwbG90KCkgKyBnZW9tX2NvbnRvdXJfZmlsbGVkKGRhdGE9Y29tcHV0ZV9wb3N0ZXJpb3JfU0Iodz0zKSwgbWFwcGluZyA9IGFlcyh4PUEsIHk9Qiwgej1Qb3N0ZXJpb3IpLCBzaG93LmxlZ2VuZD1GQUxTRSkgKwogICAgICAgICAgICAgbGFicyh0aXRsZT1wYXN0ZSgiUG9zdGVyaW9yIHdpdGggQS9CPTIgYW5kIHc9MyIpKSArCiAgICAgICAgICAgICB0aGVtZV9idygpICsKICAgICAgICAgICAgIHRoZW1lKHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KGhqdXN0PTAuNSkpLAogIG5yb3c9MSkKYGBgCgoKCiMjIyBFeGVyY2lzZSAzYgpDaGFuZ2UgdGhlIHJhdGlvIEEvQiB1c2VkIHRvIHNpbXVsYXRlIHRoZSBkYXRhIChrZWVwaW5nIGJvdGggcG9zaXRpdmUgaW4gYWNjb3JkYW5jZSB3aXRoIHRoZSBwcmlvcikuIENoZWNrIHRoZSBlZmZlY3Qgb24gdGhlIHJlc3VsdHMuCgpXZSBpbnZlc3RpZ2F0ZSB0aGUgcmF0aW9zICRBL0IgPSBceyAwLjI1LCAwLjUsIDEsIDIsIDRcfSQgYnkgZml4aW5nICRCPTEkIGFuZCBjaG9vc2luZyAkQT0gXHsgMC4yNSwgMC41LCAxLCAyLCA0XH0kLgoKYGBge3IsIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTZ9CiMgcGxvdCByZWFsIHNpZ25hbHMgdnMgbWVhc3VyZWQgc2lnbmFsIGFzIGEgZnVuY3Rpb24gb2YgQS9CCmdyaWQuYXJyYW5nZSgKcGxvdF9zaWduYWwodz0xLCBBX3RydWU9MC4yNSwgQl90cnVlPTEpLApwbG90X3NpZ25hbCh3PTEsIEFfdHJ1ZT0wLjUsIEJfdHJ1ZT0xKSwKcGxvdF9zaWduYWwodz0xLCBBX3RydWU9MSwgQl90cnVlPTEpLApwbG90X3NpZ25hbCh3PTEsIEFfdHJ1ZT0yLCBCX3RydWU9MSksCnBsb3Rfc2lnbmFsKHc9MSwgQV90cnVlPTQsIEJfdHJ1ZT0xKSwKbnJvdz0zKQpgYGAKCgoKYGBge3IsIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTZ9CiMgcGxvdCBBIHBvc3RlcmlvcgpncmlkLmFycmFuZ2UoCiAgZ2dwbG90KCkgKyBnZW9tX2xpbmUoZGF0YT1jb21wdXRlX3Bvc3Rlcmlvcl9TQihBX3RydWU9MC4yNSwgQl90cnVlPTEsIG1hcmdpbmFsaXplID0gIkEiKSwKICAgICAgICAgICAgICAgICAgICAgICBhZXMoeD1BLCB5PVBvc3RlcmlvcikpICsKICAgICAgICAgICAgIGdlb21fdmxpbmUobWFwcGluZz1hZXMoeGludGVyY2VwdCA9IDAuMjUpLCBjb2xvdXI9ImZpcmVicmljayIsIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTEpICsKICAgICAgICAgICAgIGxhYnModGl0bGU9Ik1hcmdpbmFsaXplZCBwb3N0ZXJpb3Igd2l0aCBBL0I9MC4yNSBhbmQgdz0xIikgKwogICAgICAgICAgICAgc2NhbGVfeV9jb250aW51b3VzKG5hbWU9IlAoIEEgfCBELE0gKSIpICsKICAgICAgICAgICAgIHRoZW1lX2J3KCkgKwogICAgICAgICAgICAgdGhlbWUocGxvdC50aXRsZT1lbGVtZW50X3RleHQoaGp1c3Q9MC41KSksCiAgZ2dwbG90KCkgKyBnZW9tX2xpbmUoZGF0YT1jb21wdXRlX3Bvc3Rlcmlvcl9TQihBX3RydWU9MC41LCBCX3RydWU9MSwgbWFyZ2luYWxpemUgPSAiQSIpLAogICAgICAgICAgICAgICAgICAgICAgIGFlcyh4PUEsIHk9UG9zdGVyaW9yKSkgKwogICAgICAgICAgICAgZ2VvbV92bGluZShtYXBwaW5nPWFlcyh4aW50ZXJjZXB0ID0gMC41KSwgY29sb3VyPSJmaXJlYnJpY2siLCBsaW5ldHlwZT0iZGFzaGVkIiwgc2l6ZT0xKSArCiAgICAgICAgICAgICBsYWJzKHRpdGxlPSJNYXJnaW5hbGl6ZWQgcG9zdGVyaW9yIHdpdGggQS9CPTAuNSBhbmQgdz0xIikgKwogICAgICAgICAgICAgc2NhbGVfeV9jb250aW51b3VzKG5hbWU9IlAoIEEgfCBELE0gKSIpICsKICAgICAgICAgICAgIHRoZW1lX2J3KCkgKwogICAgICAgICAgICAgdGhlbWUocGxvdC50aXRsZT1lbGVtZW50X3RleHQoaGp1c3Q9MC41KSksCiAgZ2dwbG90KCkgKyBnZW9tX2xpbmUoZGF0YT1jb21wdXRlX3Bvc3Rlcmlvcl9TQihBX3RydWU9MSwgQl90cnVlPTEsIG1hcmdpbmFsaXplID0gIkEiKSwKICAgICAgICAgICAgICAgICAgICAgICBhZXMoeD1BLCB5PVBvc3RlcmlvcikpICsKICAgICAgICAgICAgIGdlb21fdmxpbmUobWFwcGluZz1hZXMoeGludGVyY2VwdCA9IDEpLCBjb2xvdXI9ImZpcmVicmljayIsIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTEpICsKICAgICAgICAgICAgIGxhYnModGl0bGU9Ik1hcmdpbmFsaXplZCBwb3N0ZXJpb3Igd2l0aCBBL0I9MSBhbmQgdz0xIikgKwogICAgICAgICAgICAgc2NhbGVfeV9jb250aW51b3VzKG5hbWU9IlAoIEEgfCBELE0gKSIpICsKICAgICAgICAgICAgIHRoZW1lX2J3KCkgKwogICAgICAgICAgICAgdGhlbWUocGxvdC50aXRsZT1lbGVtZW50X3RleHQoaGp1c3Q9MC41KSksCiAgZ2dwbG90KCkgKyBnZW9tX2xpbmUoZGF0YT1jb21wdXRlX3Bvc3Rlcmlvcl9TQihBX3RydWU9MiwgQl90cnVlPTEsIG1hcmdpbmFsaXplID0gIkEiKSwKICAgICAgICAgICAgICAgICAgICAgICBhZXMoeD1BLCB5PVBvc3RlcmlvcikpICsKICAgICAgICAgICAgIGdlb21fdmxpbmUobWFwcGluZz1hZXMoeGludGVyY2VwdCA9IDIpLCBjb2xvdXI9ImZpcmVicmljayIsIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTEpICsKICAgICAgICAgICAgIGxhYnModGl0bGU9Ik1hcmdpbmFsaXplZCBwb3N0ZXJpb3Igd2l0aCBBL0I9MiBhbmQgdz0xIikgKwogICAgICAgICAgICAgc2NhbGVfeV9jb250aW51b3VzKG5hbWU9IlAoIEEgfCBELE0gKSIpICsKICAgICAgICAgICAgIHRoZW1lX2J3KCkgKwogICAgICAgICAgICAgdGhlbWUocGxvdC50aXRsZT1lbGVtZW50X3RleHQoaGp1c3Q9MC41KSksCiAgZ2dwbG90KCkgKyBnZW9tX2xpbmUoZGF0YT1jb21wdXRlX3Bvc3Rlcmlvcl9TQihBX3RydWU9NCwgQl90cnVlPTEsIG1hcmdpbmFsaXplID0gIkEiKSwKICAgICAgICAgICAgICAgICAgICAgICBhZXMoeD1BLCB5PVBvc3RlcmlvcikpICsKICAgICAgICAgICAgIGdlb21fdmxpbmUobWFwcGluZz1hZXMoeGludGVyY2VwdCA9IDQpLCBjb2xvdXI9ImZpcmVicmljayIsIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTEpICsKICAgICAgICAgICAgIGxhYnModGl0bGU9Ik1hcmdpbmFsaXplZCBwb3N0ZXJpb3Igd2l0aCBBL0I9NCBhbmQgdz0xIikgKwogICAgICAgICAgICAgc2NhbGVfeV9jb250aW51b3VzKG5hbWU9IlAoIEEgfCBELE0gKSIpICsKICAgICAgICAgICAgIHRoZW1lX2J3KCkgKwogICAgICAgICAgICAgdGhlbWUocGxvdC50aXRsZT1lbGVtZW50X3RleHQoaGp1c3Q9MC41KSksCiAgbnJvdz0zKQpgYGAKCgoKYGBge3IsIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTZ9CiMgcGxvdCBCIHBvc3RlcmlvcgpncmlkLmFycmFuZ2UoCiAgZ2dwbG90KCkgKyBnZW9tX2xpbmUoZGF0YT1jb21wdXRlX3Bvc3Rlcmlvcl9TQihBX3RydWU9MC4yNSwgQl90cnVlPTEsIG1hcmdpbmFsaXplID0gIkIiKSwKICAgICAgICAgICAgICAgICAgICAgICBhZXMoeD1CLCB5PVBvc3RlcmlvcikpICsKICAgICAgICAgICAgIGdlb21fdmxpbmUobWFwcGluZz1hZXMoeGludGVyY2VwdCA9IDEpLCBjb2xvdXI9ImZpcmVicmljayIsIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTEpICsKICAgICAgICAgICAgIGxhYnModGl0bGU9Ik1hcmdpbmFsaXplZCBwb3N0ZXJpb3Igd2l0aCBBL0I9MC4yNSBhbmQgdz0xIikgKwogICAgICAgICAgICAgc2NhbGVfeV9jb250aW51b3VzKG5hbWU9IlAoIEIgfCBELE0gKSIpICsKICAgICAgICAgICAgIHRoZW1lX2J3KCkgKwogICAgICAgICAgICAgdGhlbWUocGxvdC50aXRsZT1lbGVtZW50X3RleHQoaGp1c3Q9MC41KSksCiAgZ2dwbG90KCkgKyBnZW9tX2xpbmUoZGF0YT1jb21wdXRlX3Bvc3Rlcmlvcl9TQihBX3RydWU9MC41LCBCX3RydWU9MSwgbWFyZ2luYWxpemUgPSAiQiIpLAogICAgICAgICAgICAgICAgICAgICAgIGFlcyh4PUIsIHk9UG9zdGVyaW9yKSkgKwogICAgICAgICAgICAgZ2VvbV92bGluZShtYXBwaW5nPWFlcyh4aW50ZXJjZXB0ID0gMSksIGNvbG91cj0iZmlyZWJyaWNrIiwgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MSkgKwogICAgICAgICAgICAgbGFicyh0aXRsZT0iTWFyZ2luYWxpemVkIHBvc3RlcmlvciB3aXRoIEEvQj0wLjUgYW5kIHc9MSIpICsKICAgICAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhuYW1lPSJQKCBCIHwgRCxNICkiKSArCiAgICAgICAgICAgICB0aGVtZV9idygpICsKICAgICAgICAgICAgIHRoZW1lKHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KGhqdXN0PTAuNSkpLAogIGdncGxvdCgpICsgZ2VvbV9saW5lKGRhdGE9Y29tcHV0ZV9wb3N0ZXJpb3JfU0IoQV90cnVlPTEsIEJfdHJ1ZT0xLCBtYXJnaW5hbGl6ZSA9ICJCIiksCiAgICAgICAgICAgICAgICAgICAgICAgYWVzKHg9QiwgeT1Qb3N0ZXJpb3IpKSArCiAgICAgICAgICAgICBnZW9tX3ZsaW5lKG1hcHBpbmc9YWVzKHhpbnRlcmNlcHQgPSAxKSwgY29sb3VyPSJmaXJlYnJpY2siLCBsaW5ldHlwZT0iZGFzaGVkIiwgc2l6ZT0xKSArCiAgICAgICAgICAgICBsYWJzKHRpdGxlPSJNYXJnaW5hbGl6ZWQgcG9zdGVyaW9yIHdpdGggQS9CPTEgYW5kIHc9MSIpICsKICAgICAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhuYW1lPSJQKCBCIHwgRCxNICkiKSArCiAgICAgICAgICAgICB0aGVtZV9idygpICsKICAgICAgICAgICAgIHRoZW1lKHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KGhqdXN0PTAuNSkpLAogIGdncGxvdCgpICsgZ2VvbV9saW5lKGRhdGE9Y29tcHV0ZV9wb3N0ZXJpb3JfU0IoQV90cnVlPTIsIEJfdHJ1ZT0xLCBtYXJnaW5hbGl6ZSA9ICJCIiksCiAgICAgICAgICAgICAgICAgICAgICAgYWVzKHg9QiwgeT1Qb3N0ZXJpb3IpKSArCiAgICAgICAgICAgICBnZW9tX3ZsaW5lKG1hcHBpbmc9YWVzKHhpbnRlcmNlcHQgPSAxKSwgY29sb3VyPSJmaXJlYnJpY2siLCBsaW5ldHlwZT0iZGFzaGVkIiwgc2l6ZT0xKSArCiAgICAgICAgICAgICBsYWJzKHRpdGxlPSJNYXJnaW5hbGl6ZWQgcG9zdGVyaW9yIHdpdGggQS9CPTIgYW5kIHc9MSIpICsKICAgICAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhuYW1lPSJQKCBCIHwgRCxNICkiKSArCiAgICAgICAgICAgICB0aGVtZV9idygpICsKICAgICAgICAgICAgIHRoZW1lKHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KGhqdXN0PTAuNSkpLAogIGdncGxvdCgpICsgZ2VvbV9saW5lKGRhdGE9Y29tcHV0ZV9wb3N0ZXJpb3JfU0IoQV90cnVlPTQsIEJfdHJ1ZT0xLCBtYXJnaW5hbGl6ZSA9ICJCIiksCiAgICAgICAgICAgICAgICAgICAgICAgYWVzKHg9QiwgeT1Qb3N0ZXJpb3IpKSArCiAgICAgICAgICAgICBnZW9tX3ZsaW5lKG1hcHBpbmc9YWVzKHhpbnRlcmNlcHQgPSAxKSwgY29sb3VyPSJmaXJlYnJpY2siLCBsaW5ldHlwZT0iZGFzaGVkIiwgc2l6ZT0xKSArCiAgICAgICAgICAgICBsYWJzKHRpdGxlPSJNYXJnaW5hbGl6ZWQgcG9zdGVyaW9yIHdpdGggQS9CPTQgYW5kIHc9MSIpICsKICAgICAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhuYW1lPSJQKCBCIHwgRCxNICkiKSArCiAgICAgICAgICAgICB0aGVtZV9idygpICsKICAgICAgICAgICAgIHRoZW1lKHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KGhqdXN0PTAuNSkpLAogIG5yb3c9MykKYGBgCgoKYGBge3IsIGZpZy5oZWlnaHQ9NywgZmlnLndpZHRoPTV9CnBsdF9iYXNlIDwtIGdncGxvdCgpICsKICAgICAgICAgICAgdGhlbWVfYncoKSArCiAgICAgICAgICAgIHRoZW1lKHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KGhqdXN0PTAuNSkpCgpncmlkLmFycmFuZ2UoCiAgcGx0X2Jhc2UgKyBnZW9tX2NvbnRvdXJfZmlsbGVkKGRhdGE9Y29tcHV0ZV9wb3N0ZXJpb3JfU0IoQV90cnVlPTAuMjUsIEJfdHJ1ZT0xKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PUEsIHk9Qiwgej1Qb3N0ZXJpb3IpLCBzaG93LmxlZ2VuZD1GQUxTRSkgKwogICAgICAgICAgICAgZ2VvbV92bGluZShtYXBwaW5nPWFlcyh4aW50ZXJjZXB0ID0gMC4yNSksIGNvbG91cj0iZmlyZWJyaWNrIiwgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MSkgKwogICAgICAgICAgICAgZ2VvbV9obGluZShtYXBwaW5nPWFlcyh5aW50ZXJjZXB0ID0gMSksIGNvbG91cj0iZmlyZWJyaWNrIiwgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MSkgKwogICAgICAgICAgICAgbGFicyh0aXRsZT0iUG9zdGVyaW9yIHdpdGggQS9CPTAuMjUgYW5kIHc9MSIpLAogIHBsdF9iYXNlICsgZ2VvbV9jb250b3VyX2ZpbGxlZChkYXRhPWNvbXB1dGVfcG9zdGVyaW9yX1NCKEFfdHJ1ZT0wLjUsIEJfdHJ1ZT0xKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PUEsIHk9Qiwgej1Qb3N0ZXJpb3IpLCBzaG93LmxlZ2VuZD1GQUxTRSkgKwogICAgICAgICAgICAgZ2VvbV92bGluZShtYXBwaW5nPWFlcyh4aW50ZXJjZXB0ID0gMC41KSwgY29sb3VyPSJmaXJlYnJpY2siLCBsaW5ldHlwZT0iZGFzaGVkIiwgc2l6ZT0xKSArCiAgICAgICAgICAgICBnZW9tX2hsaW5lKG1hcHBpbmc9YWVzKHlpbnRlcmNlcHQgPSAxKSwgY29sb3VyPSJmaXJlYnJpY2siLCBsaW5ldHlwZT0iZGFzaGVkIiwgc2l6ZT0xKSArCiAgICAgICAgICAgICBsYWJzKHRpdGxlPSJQb3N0ZXJpb3Igd2l0aCBBL0I9MC41IGFuZCB3PTEiKSwKICBwbHRfYmFzZSArIGdlb21fY29udG91cl9maWxsZWQoZGF0YT1jb21wdXRlX3Bvc3Rlcmlvcl9TQihBX3RydWU9MSwgQl90cnVlPTEpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9QSwgeT1CLCB6PVBvc3RlcmlvciksIHNob3cubGVnZW5kPUZBTFNFKSArCiAgICAgICAgICAgICBnZW9tX3ZsaW5lKG1hcHBpbmc9YWVzKHhpbnRlcmNlcHQgPSAxKSwgY29sb3VyPSJmaXJlYnJpY2siLCBsaW5ldHlwZT0iZGFzaGVkIiwgc2l6ZT0xKSArCiAgICAgICAgICAgICBnZW9tX2hsaW5lKG1hcHBpbmc9YWVzKHlpbnRlcmNlcHQgPSAxKSwgY29sb3VyPSJmaXJlYnJpY2siLCBsaW5ldHlwZT0iZGFzaGVkIiwgc2l6ZT0xKSArCiAgICAgICAgICAgICBsYWJzKHRpdGxlPSJQb3N0ZXJpb3Igd2l0aCBBL0I9MSBhbmQgdz0xIiksCiAgcGx0X2Jhc2UgKyBnZW9tX2NvbnRvdXJfZmlsbGVkKGRhdGE9Y29tcHV0ZV9wb3N0ZXJpb3JfU0IoQV90cnVlPTIsIEJfdHJ1ZT0xKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PUEsIHk9Qiwgej1Qb3N0ZXJpb3IpLCBzaG93LmxlZ2VuZD1GQUxTRSkgKwogICAgICAgICAgICAgZ2VvbV92bGluZShtYXBwaW5nPWFlcyh4aW50ZXJjZXB0ID0gMiksIGNvbG91cj0iZmlyZWJyaWNrIiwgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MSkgKwogICAgICAgICAgICAgZ2VvbV9obGluZShtYXBwaW5nPWFlcyh5aW50ZXJjZXB0ID0gMSksIGNvbG91cj0iZmlyZWJyaWNrIiwgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MSkgKwogICAgICAgICAgICAgbGFicyh0aXRsZT0iUG9zdGVyaW9yIHdpdGggQS9CPTIgYW5kIHc9MSIpLAogIHBsdF9iYXNlICsgZ2VvbV9jb250b3VyX2ZpbGxlZChkYXRhPWNvbXB1dGVfcG9zdGVyaW9yX1NCKEFfdHJ1ZT00LCBCX3RydWU9MSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1BLCB5PUIsIHo9UG9zdGVyaW9yKSwgc2hvdy5sZWdlbmQ9RkFMU0UpICsKICAgICAgICAgICAgIGdlb21fdmxpbmUobWFwcGluZz1hZXMoeGludGVyY2VwdCA9IDQpLCBjb2xvdXI9ImZpcmVicmljayIsIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTEpICsKICAgICAgICAgICAgIGdlb21faGxpbmUobWFwcGluZz1hZXMoeWludGVyY2VwdCA9IDEpLCBjb2xvdXI9ImZpcmVicmljayIsIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTEpICsKICAgICAgICAgICAgIGxhYnModGl0bGU9IlBvc3RlcmlvciB3aXRoIEEvQj00IGFuZCB3PTEiKSwKICBucm93PTMpCmBgYAoKCgo=